OSDN Git Service

bb-reorder: Split EH edges crossing partitions.
[pf3gnuchains/gcc-fork.git] / gcc / tree-cfg.c
index e392f48..1207908 100644 (file)
@@ -1,6 +1,6 @@
 /* Control flow functions for trees.
-   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
-   Free Software Foundation, Inc.
+   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
+   2010, 2011  Free Software Foundation, Inc.
    Contributed by Diego Novillo <dnovillo@redhat.com>
 
 This file is part of GCC.
@@ -24,22 +24,20 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "tm.h"
 #include "tree.h"
-#include "rtl.h"
 #include "tm_p.h"
-#include "hard-reg-set.h"
 #include "basic-block.h"
 #include "output.h"
 #include "flags.h"
 #include "function.h"
-#include "expr.h"
 #include "ggc.h"
 #include "langhooks.h"
-#include "diagnostic.h"
+#include "tree-pretty-print.h"
+#include "gimple-pretty-print.h"
 #include "tree-flow.h"
 #include "timevar.h"
 #include "tree-dump.h"
 #include "tree-pass.h"
-#include "toplev.h"
+#include "diagnostic-core.h"
 #include "except.h"
 #include "cfgloop.h"
 #include "cfglayout.h"
@@ -71,6 +69,12 @@ static const int initial_cfg_capacity = 20;
 
 static struct pointer_map_t *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
+   due to edge manipulations.  */
+
+static bitmap touched_switch_bbs;
+
 /* CFG statistics.  */
 struct cfg_stats_d
 {
@@ -122,6 +126,7 @@ static edge find_taken_edge_computed_goto (basic_block, tree);
 static edge find_taken_edge_cond_expr (basic_block, tree);
 static edge find_taken_edge_switch_expr (basic_block, tree);
 static tree find_case_label_for_value (gimple, tree);
+static void group_case_labels_stmt (gimple);
 
 void
 init_empty_tree_cfg_for_function (struct function *fn)
@@ -144,9 +149,9 @@ init_empty_tree_cfg_for_function (struct function *fn)
                         label_to_block_map_for_function (fn),
                         initial_cfg_capacity);
 
-  SET_BASIC_BLOCK_FOR_FUNCTION (fn, ENTRY_BLOCK, 
+  SET_BASIC_BLOCK_FOR_FUNCTION (fn, ENTRY_BLOCK,
                                ENTRY_BLOCK_PTR_FOR_FUNCTION (fn));
-  SET_BASIC_BLOCK_FOR_FUNCTION (fn, EXIT_BLOCK, 
+  SET_BASIC_BLOCK_FOR_FUNCTION (fn, EXIT_BLOCK,
                   EXIT_BLOCK_PTR_FOR_FUNCTION (fn));
 
   ENTRY_BLOCK_PTR_FOR_FUNCTION (fn)->next_bb
@@ -224,10 +229,6 @@ build_gimple_cfg (gimple_seq seq)
        dump_end (TDI_vcg, vcg_file);
       }
   }
-
-#ifdef ENABLE_CHECKING
-  verify_stmts ();
-#endif
 }
 
 static unsigned int
@@ -260,8 +261,7 @@ struct gimple_opt_pass pass_build_cfg =
   PROP_cfg,                            /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_verify_stmts | TODO_cleanup_cfg
-  | TODO_dump_func                     /* todo_flags_finish */
+  TODO_verify_stmts | TODO_cleanup_cfg  /* todo_flags_finish */
  }
 };
 
@@ -431,13 +431,13 @@ create_bb (void *h, void *e, basic_block after)
   gcc_assert (!e);
 
   /* Create and initialize a new basic block.  Since alloc_block uses
-     ggc_alloc_cleared to allocate a basic block, we do not have to
-     clear the newly allocated basic block here.  */
+     GC allocation that clears memory to allocate a basic block, we do
+     not have to clear the newly allocated basic block here.  */
   bb = alloc_block ();
 
   bb->index = last_basic_block;
   bb->flags = BB_NEW;
-  bb->il.gimple = GGC_CNEW (struct gimple_bb_info);
+  bb->il.gimple = ggc_alloc_cleared_gimple_bb_info ();
   set_bb_seq (bb, h ? (gimple_seq) h : gimple_seq_alloc ());
 
   /* Add the new block to the linked list of blocks.  */
@@ -561,8 +561,12 @@ make_edges (void)
                 create abnormal edges to them.  */
              make_eh_edges (last);
 
+             /* BUILTIN_RETURN is really a return statement.  */
+             if (gimple_call_builtin_p (last, BUILT_IN_RETURN))
+               make_edge (bb, EXIT_BLOCK_PTR, 0), fallthru = false;
              /* Some calls are known not to return.  */
-             fallthru = !(gimple_call_flags (last) & ECF_NORETURN);
+             else
+               fallthru = !(gimple_call_flags (last) & ECF_NORETURN);
              break;
 
            case GIMPLE_ASSIGN:
@@ -752,7 +756,7 @@ same_line_p (location_t locus1, location_t locus2)
     return true;
   return (from.file != NULL
           && to.file != NULL
-          && strcmp (from.file, to.file) == 0);
+          && filename_cmp (from.file, to.file) == 0);
 }
 
 /* Assign a unique discriminator value to block BB if it begins at the same
@@ -833,12 +837,12 @@ edge_to_cases_cleanup (const void *key ATTRIBUTE_UNUSED, void **value,
 
   for (t = (tree) *value; t; t = next)
     {
-      next = TREE_CHAIN (t);
-      TREE_CHAIN (t) = NULL;
+      next = CASE_CHAIN (t);
+      CASE_CHAIN (t) = NULL;
     }
 
   *value = NULL;
-  return false;
+  return true;
 }
 
 /* Start recording information mapping edges to case labels.  */
@@ -848,6 +852,7 @@ start_recording_case_labels (void)
 {
   gcc_assert (edge_to_cases == NULL);
   edge_to_cases = pointer_map_create ();
+  touched_switch_bbs = BITMAP_ALLOC (NULL);
 }
 
 /* Return nonzero if we are recording information for case labels.  */
@@ -863,9 +868,22 @@ recording_case_labels_p (void)
 void
 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 = NULL;
+  EXECUTE_IF_SET_IN_BITMAP (touched_switch_bbs, 0, i, bi)
+    {
+      basic_block bb = BASIC_BLOCK (i);
+      if (bb)
+       {
+         gimple stmt = last_stmt (bb);
+         if (stmt && gimple_code (stmt) == GIMPLE_SWITCH)
+           group_case_labels_stmt (stmt);
+       }
+    }
+  BITMAP_FREE (touched_switch_bbs);
 }
 
 /* If we are inside a {start,end}_recording_cases block, then return
@@ -903,7 +921,7 @@ 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);
-      TREE_CHAIN (elt) = (tree) *slot;
+      CASE_CHAIN (elt) = (tree) *slot;
       *slot = elt;
     }
 
@@ -943,7 +961,7 @@ label_to_block_fn (struct function *ifun, tree dest)
   /* We would die hard when faced by an undefined label.  Emit a label to
      the very first basic block.  This will hopefully make even the dataflow
      and undefined variable warnings quite right.  */
-  if ((errorcount || sorrycount) && uid < 0)
+  if (seen_error () && uid < 0)
     {
       gimple_stmt_iterator gsi = gsi_start_bb (BASIC_BLOCK (NUM_FIXED_BLOCKS));
       gimple stmt;
@@ -1278,108 +1296,116 @@ cleanup_dead_labels (void)
   free (label_for_bb);
 }
 
-/* Look for blocks ending in a multiway branch (a SWITCH_EXPR in GIMPLE),
-   and scan the sorted vector of cases.  Combine the ones jumping to the
-   same label.
+/* Scan the sorted vector of cases in STMT (a GIMPLE_SWITCH) and combine
+   the ones jumping to the same label.
    Eg. three separate entries 1: 2: 3: become one entry 1..3:  */
 
-void
-group_case_labels (void)
+static void
+group_case_labels_stmt (gimple stmt)
 {
-  basic_block bb;
+  int old_size = gimple_switch_num_labels (stmt);
+  int i, j, new_size = old_size;
+  tree default_case = NULL_TREE;
+  tree default_label = NULL_TREE;
+  bool has_default;
 
-  FOR_EACH_BB (bb)
+  /* The default label is always the first case in a switch
+     statement after gimplification if it was not optimized
+     away */
+  if (!CASE_LOW (gimple_switch_default_label (stmt))
+      && !CASE_HIGH (gimple_switch_default_label (stmt)))
     {
-      gimple stmt = last_stmt (bb);
-      if (stmt && gimple_code (stmt) == GIMPLE_SWITCH)
+      default_case = gimple_switch_default_label (stmt);
+      default_label = CASE_LABEL (default_case);
+      has_default = true;
+    }
+  else
+    has_default = false;
+
+  /* Look for possible opportunities to merge cases.  */
+  if (has_default)
+    i = 1;
+  else
+    i = 0;
+  while (i < old_size)
+    {
+      tree base_case, base_label, base_high;
+      base_case = gimple_switch_label (stmt, i);
+
+      gcc_assert (base_case);
+      base_label = CASE_LABEL (base_case);
+
+      /* Discard cases that have the same destination as the
+        default case.  */
+      if (base_label == default_label)
+       {
+         gimple_switch_set_label (stmt, i, NULL_TREE);
+         i++;
+         new_size--;
+         continue;
+       }
+
+      base_high = CASE_HIGH (base_case)
+         ? CASE_HIGH (base_case)
+         : CASE_LOW (base_case);
+      i++;
+
+      /* Try to merge case labels.  Break out when we reach the end
+        of the label vector or when we cannot merge the next case
+        label with the current one.  */
+      while (i < old_size)
        {
-         int old_size = gimple_switch_num_labels (stmt);
-         int i, j, new_size = old_size;
-         tree default_case = NULL_TREE;
-         tree default_label = NULL_TREE;
-         bool has_default;
-
-         /* The default label is always the first case in a switch
-            statement after gimplification if it was not optimized
-            away */
-         if (!CASE_LOW (gimple_switch_default_label (stmt))
-             && !CASE_HIGH (gimple_switch_default_label (stmt)))
+         tree merge_case = gimple_switch_label (stmt, i);
+         tree merge_label = CASE_LABEL (merge_case);
+         double_int bhp1 = double_int_add (tree_to_double_int (base_high),
+                                           double_int_one);
+
+         /* Merge the cases if they jump to the same place,
+            and their ranges are consecutive.  */
+         if (merge_label == base_label
+             && double_int_equal_p (tree_to_double_int (CASE_LOW (merge_case)),
+                                    bhp1))
            {
-             default_case = gimple_switch_default_label (stmt);
-             default_label = CASE_LABEL (default_case);
-             has_default = true;
+             base_high = CASE_HIGH (merge_case) ?
+                 CASE_HIGH (merge_case) : CASE_LOW (merge_case);
+             CASE_HIGH (base_case) = base_high;
+             gimple_switch_set_label (stmt, i, NULL_TREE);
+             new_size--;
+             i++;
            }
          else
-           has_default = false;
-
-         /* Look for possible opportunities to merge cases.  */
-         if (has_default)
-           i = 1;
-         else
-           i = 0;
-         while (i < old_size)
-           {
-             tree base_case, base_label, base_high;
-             base_case = gimple_switch_label (stmt, i);
-
-             gcc_assert (base_case);
-             base_label = CASE_LABEL (base_case);
+           break;
+       }
+    }
 
-             /* Discard cases that have the same destination as the
-                default case.  */
-             if (base_label == default_label)
-               {
-                 gimple_switch_set_label (stmt, i, NULL_TREE);
-                 i++;
-                 new_size--;
-                 continue;
-               }
+  /* Compress the case labels in the label vector, and adjust the
+     length of the vector.  */
+  for (i = 0, j = 0; i < new_size; i++)
+    {
+      while (! gimple_switch_label (stmt, j))
+       j++;
+      gimple_switch_set_label (stmt, i,
+                              gimple_switch_label (stmt, j++));
+    }
 
-             base_high = CASE_HIGH (base_case)
-                         ? CASE_HIGH (base_case)
-                         : CASE_LOW (base_case);
-             i++;
+  gcc_assert (new_size <= old_size);
+  gimple_switch_set_num_labels (stmt, new_size);
+}
 
-             /* Try to merge case labels.  Break out when we reach the end
-                of the label vector or when we cannot merge the next case
-                label with the current one.  */
-             while (i < old_size)
-               {
-                 tree merge_case = gimple_switch_label (stmt, i);
-                 tree merge_label = CASE_LABEL (merge_case);
-                 tree t = int_const_binop (PLUS_EXPR, base_high,
-                                           integer_one_node, 1);
-
-                 /* Merge the cases if they jump to the same place,
-                    and their ranges are consecutive.  */
-                 if (merge_label == base_label
-                     && tree_int_cst_equal (CASE_LOW (merge_case), t))
-                   {
-                     base_high = CASE_HIGH (merge_case) ?
-                       CASE_HIGH (merge_case) : CASE_LOW (merge_case);
-                     CASE_HIGH (base_case) = base_high;
-                     gimple_switch_set_label (stmt, i, NULL_TREE);
-                     new_size--;
-                     i++;
-                   }
-                 else
-                   break;
-               }
-           }
+/* Look for blocks ending in a multiway branch (a GIMPLE_SWITCH),
+   and scan the sorted vector of cases.  Combine the ones jumping to the
+   same label.  */
 
-         /* Compress the case labels in the label vector, and adjust the
-            length of the vector.  */
-         for (i = 0, j = 0; i < new_size; i++)
-           {
-             while (! gimple_switch_label (stmt, j))
-               j++;
-             gimple_switch_set_label (stmt, i,
-                                      gimple_switch_label (stmt, j++));
-           }
+void
+group_case_labels (void)
+{
+  basic_block bb;
 
-         gcc_assert (new_size <= old_size);
-         gimple_switch_set_num_labels (stmt, new_size);
-       }
+  FOR_EACH_BB (bb)
+    {
+      gimple stmt = last_stmt (bb);
+      if (stmt && gimple_code (stmt) == GIMPLE_SWITCH)
+       group_case_labels_stmt (stmt);
     }
 }
 
@@ -1395,7 +1421,7 @@ gimple_can_merge_blocks_p (basic_block a, basic_block b)
   if (!single_succ_p (a))
     return false;
 
-  if (single_succ_edge (a)->flags & (EDGE_ABNORMAL | EDGE_EH))
+  if (single_succ_edge (a)->flags & (EDGE_ABNORMAL | EDGE_EH | EDGE_PRESERVE))
     return false;
 
   if (single_succ (a) != b)
@@ -1438,26 +1464,28 @@ gimple_can_merge_blocks_p (basic_block a, basic_block b)
     return false;
 
   /* It must be possible to eliminate all phi nodes in B.  If ssa form
-     is not up-to-date, we cannot eliminate any phis; however, if only
-     some symbols as whole are marked for renaming, this is not a problem,
-     as phi nodes for those symbols are irrelevant in updating anyway.  */
+     is not up-to-date and a name-mapping is registered, we cannot eliminate
+     any phis.  Symbols marked for renaming are never a problem though.  */
   phis = phi_nodes (b);
-  if (!gimple_seq_empty_p (phis))
-    {
-      gimple_stmt_iterator i;
+  if (!gimple_seq_empty_p (phis)
+      && name_mappings_registered_p ())
+    return false;
 
-      if (name_mappings_registered_p ())
+  /* When not optimizing, don't merge if we'd lose goto_locus.  */
+  if (!optimize
+      && single_succ_edge (a)->goto_locus != UNKNOWN_LOCATION)
+    {
+      location_t goto_locus = single_succ_edge (a)->goto_locus;
+      gimple_stmt_iterator prev, next;
+      prev = gsi_last_nondebug_bb (a);
+      next = gsi_after_labels (b);
+      if (!gsi_end_p (next) && is_gimple_debug (gsi_stmt (next)))
+       gsi_next_nondebug (&next);
+      if ((gsi_end_p (prev)
+          || gimple_location (gsi_stmt (prev)) != goto_locus)
+         && (gsi_end_p (next)
+             || gimple_location (gsi_stmt (next)) != goto_locus))
        return false;
-
-      for (i = gsi_start (phis); !gsi_end_p (i); gsi_next (&i))
-       {
-         gimple phi = gsi_stmt (i);
-
-         if (!is_gimple_reg (gimple_phi_result (phi))
-             && !may_propagate_copy (gimple_phi_result (phi),
-                                     gimple_phi_arg_def (phi, 0)))
-           return false;
-       }
     }
 
   return true;
@@ -1541,7 +1569,7 @@ replace_uses_by (tree name, tree val)
          size_t i;
 
          fold_stmt_inplace (stmt);
-         if (cfgcleanup_altered_bbs)
+         if (cfgcleanup_altered_bbs && !is_gimple_debug (stmt))
            bitmap_set_bit (cfgcleanup_altered_bbs, gimple_bb (stmt)->index);
 
          /* FIXME.  This should go in update_stmt.  */
@@ -1632,6 +1660,9 @@ gimple_merge_blocks (basic_block a, basic_block b)
              FOR_EACH_IMM_USE_STMT (stmt, iter, def)
                FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
                  SET_USE (use_p, use);
+
+             if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (def))
+               SSA_NAME_OCCURS_IN_ABNORMAL_PHI (use) = 1;
            }
          else
             replace_uses_by (def, use);
@@ -1715,814 +1746,199 @@ single_noncomplex_succ (basic_block bb)
   return bb;
 }
 
+/* T is CALL_EXPR.  Set current_function_calls_* flags.  */
 
-/* Walk the function tree removing unnecessary statements.
-
-     * Empty statement nodes are removed
-
-     * Unnecessary TRY_FINALLY and TRY_CATCH blocks are removed
+void
+notice_special_calls (gimple call)
+{
+  int flags = gimple_call_flags (call);
 
-     * Unnecessary COND_EXPRs are removed
+  if (flags & ECF_MAY_BE_ALLOCA)
+    cfun->calls_alloca = true;
+  if (flags & ECF_RETURNS_TWICE)
+    cfun->calls_setjmp = true;
+}
 
-     * Some unnecessary BIND_EXPRs are removed
 
-     * GOTO_EXPRs immediately preceding destination are removed.
+/* Clear flags set by notice_special_calls.  Used by dead code removal
+   to update the flags.  */
 
-   Clearly more work could be done.  The trick is doing the analysis
-   and removal fast enough to be a net improvement in compile times.
+void
+clear_special_calls (void)
+{
+  cfun->calls_alloca = false;
+  cfun->calls_setjmp = false;
+}
 
-   Note that when we remove a control structure such as a COND_EXPR
-   BIND_EXPR, or TRY block, we will need to repeat this optimization pass
-   to ensure we eliminate all the useless code.  */
+/* Remove PHI nodes associated with basic block BB and all edges out of BB.  */
 
-struct rus_data
+static void
+remove_phi_nodes_and_edges_for_unreachable_block (basic_block bb)
 {
-  bool repeat;
-  bool may_throw;
-  bool may_branch;
-  bool has_label;
-  bool last_was_goto;
-  gimple_stmt_iterator last_goto_gsi;
-};
+  /* Since this block is no longer reachable, we can just delete all
+     of its PHI nodes.  */
+  remove_phi_nodes (bb);
 
+  /* Remove edges to BB's successors.  */
+  while (EDGE_COUNT (bb->succs) > 0)
+    remove_edge (EDGE_SUCC (bb, 0));
+}
 
-static void remove_useless_stmts_1 (gimple_stmt_iterator *gsi, struct rus_data *);
 
-/* Given a statement sequence, find the first executable statement with
-   location information, and warn that it is unreachable.  When searching,
-   descend into containers in execution order.  */
+/* Remove statements of basic block BB.  */
 
-static bool
-remove_useless_stmts_warn_notreached (gimple_seq stmts)
+static void
+remove_bb (basic_block bb)
 {
-  gimple_stmt_iterator gsi;
+  gimple_stmt_iterator i;
 
-  for (gsi = gsi_start (stmts); !gsi_end_p (gsi); gsi_next (&gsi))
+  if (dump_file)
     {
-      gimple stmt = gsi_stmt (gsi);
-
-      if (gimple_no_warning_p (stmt)) return false;
+      fprintf (dump_file, "Removing basic block %d\n", bb->index);
+      if (dump_flags & TDF_DETAILS)
+       {
+         dump_bb (bb, dump_file, 0);
+         fprintf (dump_file, "\n");
+       }
+    }
 
-      if (gimple_has_location (stmt))
-        {
-          location_t loc = gimple_location (stmt);
-          if (LOCATION_LINE (loc) > 0)
-           {
-              warning_at (loc, OPT_Wunreachable_code, "will never be executed");
-              return true;
-            }
-        }
+  if (current_loops)
+    {
+      struct loop *loop = bb->loop_father;
 
-      switch (gimple_code (stmt))
-        {
-        /* Unfortunately, we need the CFG now to detect unreachable
-           branches in a conditional, so conditionals are not handled here.  */
+      /* If a loop gets removed, clean up the information associated
+        with it.  */
+      if (loop->latch == bb
+         || loop->header == bb)
+       free_numbers_of_iterations_estimates_loop (loop);
+    }
 
-        case GIMPLE_TRY:
-          if (remove_useless_stmts_warn_notreached (gimple_try_eval (stmt)))
-            return true;
-          if (remove_useless_stmts_warn_notreached (gimple_try_cleanup (stmt)))
-            return true;
-          break;
+  /* Remove all the instructions in the block.  */
+  if (bb_seq (bb) != NULL)
+    {
+      /* Walk backwards so as to get a chance to substitute all
+        released DEFs into debug stmts.  See
+        eliminate_unnecessary_stmts() in tree-ssa-dce.c for more
+        details.  */
+      for (i = gsi_last_bb (bb); !gsi_end_p (i);)
+       {
+         gimple stmt = gsi_stmt (i);
+         if (gimple_code (stmt) == GIMPLE_LABEL
+             && (FORCED_LABEL (gimple_label_label (stmt))
+                 || DECL_NONLOCAL (gimple_label_label (stmt))))
+           {
+             basic_block new_bb;
+             gimple_stmt_iterator new_gsi;
 
-        case GIMPLE_CATCH:
-          return remove_useless_stmts_warn_notreached (gimple_catch_handler (stmt));
+             /* A non-reachable non-local label may still be referenced.
+                But it no longer needs to carry the extra semantics of
+                non-locality.  */
+             if (DECL_NONLOCAL (gimple_label_label (stmt)))
+               {
+                 DECL_NONLOCAL (gimple_label_label (stmt)) = 0;
+                 FORCED_LABEL (gimple_label_label (stmt)) = 1;
+               }
 
-        case GIMPLE_EH_FILTER:
-          return remove_useless_stmts_warn_notreached (gimple_eh_filter_failure (stmt));
+             new_bb = bb->prev_bb;
+             new_gsi = gsi_start_bb (new_bb);
+             gsi_remove (&i, false);
+             gsi_insert_before (&new_gsi, stmt, GSI_NEW_STMT);
+           }
+         else
+           {
+             /* Release SSA definitions if we are in SSA.  Note that we
+                may be called when not in SSA.  For example,
+                final_cleanup calls this function via
+                cleanup_tree_cfg.  */
+             if (gimple_in_ssa_p (cfun))
+               release_defs (stmt);
 
-        case GIMPLE_BIND:
-          return remove_useless_stmts_warn_notreached (gimple_bind_body (stmt));
+             gsi_remove (&i, true);
+           }
 
-        default:
-          break;
-        }
+         if (gsi_end_p (i))
+           i = gsi_last_bb (bb);
+         else
+           gsi_prev (&i);
+       }
     }
 
-  return false;
+  remove_phi_nodes_and_edges_for_unreachable_block (bb);
+  bb->il.gimple = NULL;
 }
 
-/* Helper for remove_useless_stmts_1.  Handle GIMPLE_COND statements.  */
 
-static void
-remove_useless_stmts_cond (gimple_stmt_iterator *gsi, struct rus_data *data)
+/* Given a basic block BB ending with COND_EXPR or SWITCH_EXPR, and a
+   predicate VAL, return the edge that will be taken out of the block.
+   If VAL does not match a unique edge, NULL is returned.  */
+
+edge
+find_taken_edge (basic_block bb, tree val)
 {
-  gimple stmt = gsi_stmt (*gsi);
+  gimple stmt;
 
-  /* The folded result must still be a conditional statement.  */
-  fold_stmt (gsi);
-  gcc_assert (gsi_stmt (*gsi) == stmt);
+  stmt = last_stmt (bb);
 
-  data->may_branch = true;
+  gcc_assert (stmt);
+  gcc_assert (is_ctrl_stmt (stmt));
 
-  /* Replace trivial conditionals with gotos. */
-  if (gimple_cond_true_p (stmt))
-    {
-      /* Goto THEN label.  */
-      tree then_label = gimple_cond_true_label (stmt);
+  if (val == NULL)
+    return NULL;
 
-      gsi_replace (gsi, gimple_build_goto (then_label), false);
-      data->last_goto_gsi = *gsi;
-      data->last_was_goto = true;
-      data->repeat = true;
-    }
-  else if (gimple_cond_false_p (stmt))
-    {
-      /* Goto ELSE label.  */
-      tree else_label = gimple_cond_false_label (stmt);
+  if (!is_gimple_min_invariant (val))
+    return NULL;
 
-      gsi_replace (gsi, gimple_build_goto (else_label), false);
-      data->last_goto_gsi = *gsi;
-      data->last_was_goto = true;
-      data->repeat = true;
-    }
-  else
+  if (gimple_code (stmt) == GIMPLE_COND)
+    return find_taken_edge_cond_expr (bb, val);
+
+  if (gimple_code (stmt) == GIMPLE_SWITCH)
+    return find_taken_edge_switch_expr (bb, val);
+
+  if (computed_goto_p (stmt))
     {
-      tree then_label = gimple_cond_true_label (stmt);
-      tree else_label = gimple_cond_false_label (stmt);
+      /* Only optimize if the argument is a label, if the argument is
+        not a label then we can not construct a proper CFG.
 
-      if (then_label == else_label)
-        {
-          /* Goto common destination.  */
-          gsi_replace (gsi, gimple_build_goto (then_label), false);
-          data->last_goto_gsi = *gsi;
-          data->last_was_goto = true;
-         data->repeat = true;
-       }
+         It may be the case that we only need to allow the LABEL_REF to
+         appear inside an ADDR_EXPR, but we also allow the LABEL_REF to
+         appear inside a LABEL_EXPR just to be safe.  */
+      if ((TREE_CODE (val) == ADDR_EXPR || TREE_CODE (val) == LABEL_EXPR)
+         && TREE_CODE (TREE_OPERAND (val, 0)) == LABEL_DECL)
+       return find_taken_edge_computed_goto (bb, TREE_OPERAND (val, 0));
+      return NULL;
     }
 
-  gsi_next (gsi);
-
-  data->last_was_goto = false;
+  gcc_unreachable ();
 }
 
-/* Helper for remove_useless_stmts_1. 
-   Handle the try-finally case for GIMPLE_TRY statements.  */
+/* Given a constant value VAL and the entry block BB to a GOTO_EXPR
+   statement, determine which of the outgoing edges will be taken out of the
+   block.  Return NULL if either edge may be taken.  */
 
-static void
-remove_useless_stmts_tf (gimple_stmt_iterator *gsi, struct rus_data *data)
+static edge
+find_taken_edge_computed_goto (basic_block bb, tree val)
 {
-  bool save_may_branch, save_may_throw;
-  bool this_may_branch, this_may_throw;
-
-  gimple_seq eval_seq, cleanup_seq;
-  gimple_stmt_iterator eval_gsi, cleanup_gsi;
-
-  gimple stmt = gsi_stmt (*gsi);
-
-  /* Collect may_branch and may_throw information for the body only.  */
-  save_may_branch = data->may_branch;
-  save_may_throw = data->may_throw;
-  data->may_branch = false;
-  data->may_throw = false;
-  data->last_was_goto = false;
-
-  eval_seq = gimple_try_eval (stmt);
-  eval_gsi = gsi_start (eval_seq);
-  remove_useless_stmts_1 (&eval_gsi, data);
-
-  this_may_branch = data->may_branch;
-  this_may_throw = data->may_throw;
-  data->may_branch |= save_may_branch;
-  data->may_throw |= save_may_throw;
-  data->last_was_goto = false;
-
-  cleanup_seq = gimple_try_cleanup (stmt);
-  cleanup_gsi = gsi_start (cleanup_seq);
-  remove_useless_stmts_1 (&cleanup_gsi, data);
-
-  /* If the body is empty, then we can emit the FINALLY block without
-     the enclosing TRY_FINALLY_EXPR.  */
-  if (gimple_seq_empty_p (eval_seq))
-    {
-      gsi_insert_seq_before (gsi, cleanup_seq, GSI_SAME_STMT);
-      gsi_remove (gsi, false);
-      data->repeat = true;
-    }
+  basic_block dest;
+  edge e = NULL;
 
-  /* If the handler is empty, then we can emit the TRY block without
-     the enclosing TRY_FINALLY_EXPR.  */
-  else if (gimple_seq_empty_p (cleanup_seq))
+  dest = label_to_block (val);
+  if (dest)
     {
-      gsi_insert_seq_before (gsi, eval_seq, GSI_SAME_STMT);
-      gsi_remove (gsi, false);
-      data->repeat = true;
+      e = find_edge (bb, dest);
+      gcc_assert (e != NULL);
     }
 
-  /* If the body neither throws, nor branches, then we can safely
-     string the TRY and FINALLY blocks together.  */
-  else if (!this_may_branch && !this_may_throw)
-    {
-      gsi_insert_seq_before (gsi, eval_seq, GSI_SAME_STMT);
-      gsi_insert_seq_before (gsi, cleanup_seq, GSI_SAME_STMT);
-      gsi_remove (gsi, false);
-      data->repeat = true;
-    }
-  else
-    gsi_next (gsi);
+  return e;
 }
 
-/* Helper for remove_useless_stmts_1. 
-   Handle the try-catch case for GIMPLE_TRY statements.  */
+/* Given a constant value VAL and the entry block BB to a COND_EXPR
+   statement, determine which of the two edges will be taken out of the
+   block.  Return NULL if either edge may be taken.  */
 
-static void
-remove_useless_stmts_tc (gimple_stmt_iterator *gsi, struct rus_data *data)
+static edge
+find_taken_edge_cond_expr (basic_block bb, tree val)
 {
-  bool save_may_throw, this_may_throw;
-
-  gimple_seq eval_seq, cleanup_seq, handler_seq, failure_seq;
-  gimple_stmt_iterator eval_gsi, cleanup_gsi, handler_gsi, failure_gsi;
-
-  gimple stmt = gsi_stmt (*gsi);
-
-  /* Collect may_throw information for the body only.  */
-  save_may_throw = data->may_throw;
-  data->may_throw = false;
-  data->last_was_goto = false;
-
-  eval_seq = gimple_try_eval (stmt);
-  eval_gsi = gsi_start (eval_seq);
-  remove_useless_stmts_1 (&eval_gsi, data);
-
-  this_may_throw = data->may_throw;
-  data->may_throw = save_may_throw;
-
-  cleanup_seq = gimple_try_cleanup (stmt);
-
-  /* If the body cannot throw, then we can drop the entire TRY_CATCH_EXPR.  */
-  if (!this_may_throw)
-    {
-      if (warn_notreached)
-        {
-          remove_useless_stmts_warn_notreached (cleanup_seq);
-        }
-      gsi_insert_seq_before (gsi, eval_seq, GSI_SAME_STMT);
-      gsi_remove (gsi, false);
-      data->repeat = true;
-      return;
-    }
-
-  /* Process the catch clause specially.  We may be able to tell that
-     no exceptions propagate past this point.  */
-
-  this_may_throw = true;
-  cleanup_gsi = gsi_start (cleanup_seq);
-  stmt = gsi_stmt (cleanup_gsi);
-  data->last_was_goto = false;
-
-  switch (gimple_code (stmt))
-    {
-    case GIMPLE_CATCH:
-      /* If the first element is a catch, they all must be.  */
-      while (!gsi_end_p (cleanup_gsi))
-        {
-         stmt = gsi_stmt (cleanup_gsi);
-         /* If we catch all exceptions, then the body does not
-            propagate exceptions past this point.  */
-         if (gimple_catch_types (stmt) == NULL)
-           this_may_throw = false;
-         data->last_was_goto = false;
-          handler_seq = gimple_catch_handler (stmt);
-          handler_gsi = gsi_start (handler_seq);
-         remove_useless_stmts_1 (&handler_gsi, data);
-          gsi_next (&cleanup_gsi);
-       }
-      gsi_next (gsi);
-      break;
-
-    case GIMPLE_EH_FILTER:
-      if (gimple_eh_filter_types (stmt) == NULL)
-       this_may_throw = false;
-      failure_seq = gimple_eh_filter_failure (stmt);
-      failure_gsi = gsi_start (failure_seq);
-      remove_useless_stmts_1 (&failure_gsi, data);
-      gsi_next (gsi);
-      break;
-
-    case GIMPLE_EH_MUST_NOT_THROW:
-      this_may_throw = false;
-      gsi_next (gsi);
-      break;
-
-    default:
-      /* Otherwise this is a list of cleanup statements.  */
-      remove_useless_stmts_1 (&cleanup_gsi, data);
-
-      /* If the cleanup is empty, then we can emit the TRY block without
-        the enclosing TRY_CATCH_EXPR.  */
-      if (gimple_seq_empty_p (cleanup_seq))
-       {
-          gsi_insert_seq_before (gsi, eval_seq, GSI_SAME_STMT);
-          gsi_remove(gsi, false);
-         data->repeat = true;
-       }
-      else
-        gsi_next (gsi);
-      break;
-    }
-
-  data->may_throw |= this_may_throw;
-}
-
-/* Helper for remove_useless_stmts_1.  Handle GIMPLE_BIND statements.  */
-
-static void
-remove_useless_stmts_bind (gimple_stmt_iterator *gsi, struct rus_data *data ATTRIBUTE_UNUSED)
-{
-  tree block;
-  gimple_seq body_seq, fn_body_seq;
-  gimple_stmt_iterator body_gsi;
-
-  gimple stmt = gsi_stmt (*gsi);
-
-  /* First remove anything underneath the BIND_EXPR.  */
-  
-  body_seq = gimple_bind_body (stmt);
-  body_gsi = gsi_start (body_seq);
-  remove_useless_stmts_1 (&body_gsi, data);
-
-  /* If the GIMPLE_BIND has no variables, then we can pull everything
-     up one level and remove the GIMPLE_BIND, unless this is the toplevel
-     GIMPLE_BIND for the current function or an inlined function.
-
-     When this situation occurs we will want to apply this
-     optimization again.  */
-  block = gimple_bind_block (stmt);
-  fn_body_seq = gimple_body (current_function_decl);
-  if (gimple_bind_vars (stmt) == NULL_TREE
-      && (gimple_seq_empty_p (fn_body_seq)
-          || stmt != gimple_seq_first_stmt (fn_body_seq))
-      && (! block
-         || ! BLOCK_ABSTRACT_ORIGIN (block)
-         || (TREE_CODE (BLOCK_ABSTRACT_ORIGIN (block))
-             != FUNCTION_DECL)))
-    {
-      tree var = NULL_TREE;
-      /* Even if there are no gimple_bind_vars, there might be other
-        decls in BLOCK_VARS rendering the GIMPLE_BIND not useless.  */
-      if (block && !BLOCK_NUM_NONLOCALIZED_VARS (block))
-       for (var = BLOCK_VARS (block); var; var = TREE_CHAIN (var))
-         if (TREE_CODE (var) == IMPORTED_DECL)
-           break;
-      if (var || (block && BLOCK_NUM_NONLOCALIZED_VARS (block)))
-       gsi_next (gsi);
-      else
-       {
-         gsi_insert_seq_before (gsi, body_seq, GSI_SAME_STMT);
-         gsi_remove (gsi, false);
-         data->repeat = true;
-       }
-    }
-  else
-    gsi_next (gsi);
-}
-
-/* Helper for remove_useless_stmts_1.  Handle GIMPLE_GOTO statements.  */
-
-static void
-remove_useless_stmts_goto (gimple_stmt_iterator *gsi, struct rus_data *data)
-{
-  gimple stmt = gsi_stmt (*gsi);
-
-  tree dest = gimple_goto_dest (stmt);
-
-  data->may_branch = true;
-  data->last_was_goto = false;
-
-  /* Record iterator for last goto expr, so that we can delete it if unnecessary.  */
-  if (TREE_CODE (dest) == LABEL_DECL)
-    {
-      data->last_goto_gsi = *gsi;
-      data->last_was_goto = true;
-    }
-
-  gsi_next(gsi);
-}
-
-/* Helper for remove_useless_stmts_1.  Handle GIMPLE_LABEL statements.  */
-
-static void
-remove_useless_stmts_label (gimple_stmt_iterator *gsi, struct rus_data *data)
-{
-  gimple stmt = gsi_stmt (*gsi);
-
-  tree label = gimple_label_label (stmt);
-
-  data->has_label = true;
-
-  /* We do want to jump across non-local label receiver code.  */
-  if (DECL_NONLOCAL (label))
-    data->last_was_goto = false;
-
-  else if (data->last_was_goto
-           && gimple_goto_dest (gsi_stmt (data->last_goto_gsi)) == label)
-    {
-      /* Replace the preceding GIMPLE_GOTO statement with
-         a GIMPLE_NOP, which will be subsequently removed.
-         In this way, we avoid invalidating other iterators
-         active on the statement sequence.  */
-      gsi_replace(&data->last_goto_gsi, gimple_build_nop(), false);
-      data->last_was_goto = false;
-      data->repeat = true;
-    }
-
-  /* ??? Add something here to delete unused labels.  */
-
-  gsi_next (gsi);
-}
-
-
-/* T is CALL_EXPR.  Set current_function_calls_* flags.  */
-
-void
-notice_special_calls (gimple call)
-{
-  int flags = gimple_call_flags (call);
-
-  if (flags & ECF_MAY_BE_ALLOCA)
-    cfun->calls_alloca = true;
-  if (flags & ECF_RETURNS_TWICE)
-    cfun->calls_setjmp = true;
-}
-
-
-/* Clear flags set by notice_special_calls.  Used by dead code removal
-   to update the flags.  */
-
-void
-clear_special_calls (void)
-{
-  cfun->calls_alloca = false;
-  cfun->calls_setjmp = false;
-}
-
-/* Remove useless statements from a statement sequence, and perform
-   some preliminary simplifications.  */
-
-static void
-remove_useless_stmts_1 (gimple_stmt_iterator *gsi, struct rus_data *data)
-{
-  while (!gsi_end_p (*gsi))
-    {
-      gimple stmt = gsi_stmt (*gsi);
-
-      switch (gimple_code (stmt))
-        {
-        case GIMPLE_COND:
-          remove_useless_stmts_cond (gsi, data);
-          break;
-
-        case GIMPLE_GOTO:
-          remove_useless_stmts_goto (gsi, data);
-          break;
-
-        case GIMPLE_LABEL:
-          remove_useless_stmts_label (gsi, data);
-          break;
-
-        case GIMPLE_ASSIGN:
-          fold_stmt (gsi);
-          stmt = gsi_stmt (*gsi);
-          data->last_was_goto = false;
-          if (stmt_could_throw_p (stmt))
-            data->may_throw = true;
-          gsi_next (gsi);
-          break;
-
-        case GIMPLE_ASM:
-          fold_stmt (gsi);
-          data->last_was_goto = false;
-          gsi_next (gsi);
-          break;
-
-        case GIMPLE_CALL:
-          fold_stmt (gsi);
-          stmt = gsi_stmt (*gsi);
-          data->last_was_goto = false;
-          if (is_gimple_call (stmt))
-            notice_special_calls (stmt);
-
-          /* We used to call update_gimple_call_flags here,
-             which copied side-effects and nothrows status
-             from the function decl to the call.  In the new
-             tuplified GIMPLE, the accessors for this information
-             always consult the function decl, so this copying
-             is no longer necessary.  */
-          if (stmt_could_throw_p (stmt))
-            data->may_throw = true;
-          gsi_next (gsi);
-          break;
-
-        case GIMPLE_RETURN:
-          fold_stmt (gsi);
-          data->last_was_goto = false;
-          data->may_branch = true;
-          gsi_next (gsi);
-          break;
-
-        case GIMPLE_BIND:
-          remove_useless_stmts_bind (gsi, data);
-          break;
-
-        case GIMPLE_TRY:
-          if (gimple_try_kind (stmt) == GIMPLE_TRY_CATCH)
-            remove_useless_stmts_tc (gsi, data);
-          else if (gimple_try_kind (stmt) == GIMPLE_TRY_FINALLY)
-            remove_useless_stmts_tf (gsi, data);
-          else
-            gcc_unreachable ();
-          break;
-
-        case GIMPLE_CATCH:
-          gcc_unreachable ();
-          break;
-
-        case GIMPLE_NOP:
-          gsi_remove (gsi, false);
-          break;
-
-        case GIMPLE_OMP_FOR:
-          {
-            gimple_seq pre_body_seq = gimple_omp_for_pre_body (stmt);
-            gimple_stmt_iterator pre_body_gsi = gsi_start (pre_body_seq);
-
-            remove_useless_stmts_1 (&pre_body_gsi, data);
-           data->last_was_goto = false;
-          }
-          /* FALLTHROUGH */
-        case GIMPLE_OMP_CRITICAL:
-        case GIMPLE_OMP_CONTINUE:
-        case GIMPLE_OMP_MASTER:
-        case GIMPLE_OMP_ORDERED:
-        case GIMPLE_OMP_SECTION:
-        case GIMPLE_OMP_SECTIONS:
-        case GIMPLE_OMP_SINGLE:
-          {
-            gimple_seq body_seq = gimple_omp_body (stmt);
-            gimple_stmt_iterator body_gsi = gsi_start (body_seq);
-
-            remove_useless_stmts_1 (&body_gsi, data);
-           data->last_was_goto = false;
-           gsi_next (gsi);
-          }
-          break;
-
-        case GIMPLE_OMP_PARALLEL:
-       case GIMPLE_OMP_TASK:
-          {
-           /* Make sure the outermost GIMPLE_BIND isn't removed
-              as useless.  */
-            gimple_seq body_seq = gimple_omp_body (stmt);
-            gimple bind = gimple_seq_first_stmt (body_seq);
-            gimple_seq bind_seq = gimple_bind_body (bind);
-            gimple_stmt_iterator bind_gsi = gsi_start (bind_seq);
-
-            remove_useless_stmts_1 (&bind_gsi, data);
-           data->last_was_goto = false;
-           gsi_next (gsi);
-          }
-          break;
-
-        default:
-          data->last_was_goto = false;
-          gsi_next (gsi);
-          break;
-        }
-    }
-}
-
-/* Walk the function tree, removing useless statements and performing
-   some preliminary simplifications.  */
-
-static unsigned int
-remove_useless_stmts (void)
-{
-  struct rus_data data;
-
-  clear_special_calls ();
-
-  do
-    {
-      gimple_stmt_iterator gsi;
-
-      gsi = gsi_start (gimple_body (current_function_decl));
-      memset (&data, 0, sizeof (data));
-      remove_useless_stmts_1 (&gsi, &data);
-    }
-  while (data.repeat);
-
-#ifdef ENABLE_TYPES_CHECKING
-  verify_types_in_gimple_seq (gimple_body (current_function_decl));
-#endif
-
-  return 0;
-}
-
-
-struct gimple_opt_pass pass_remove_useless_stmts =
-{
- {
-  GIMPLE_PASS,
-  "useless",                           /* name */
-  NULL,                                        /* gate */
-  remove_useless_stmts,                        /* execute */
-  NULL,                                        /* sub */
-  NULL,                                        /* next */
-  0,                                   /* static_pass_number */
-  TV_NONE,                             /* tv_id */
-  PROP_gimple_any,                     /* properties_required */
-  0,                                   /* properties_provided */
-  0,                                   /* properties_destroyed */
-  0,                                   /* todo_flags_start */
-  TODO_dump_func                       /* todo_flags_finish */
- }
-};
-
-/* Remove PHI nodes associated with basic block BB and all edges out of BB.  */
-
-static void
-remove_phi_nodes_and_edges_for_unreachable_block (basic_block bb)
-{
-  /* Since this block is no longer reachable, we can just delete all
-     of its PHI nodes.  */
-  remove_phi_nodes (bb);
-
-  /* Remove edges to BB's successors.  */
-  while (EDGE_COUNT (bb->succs) > 0)
-    remove_edge (EDGE_SUCC (bb, 0));
-}
-
-
-/* Remove statements of basic block BB.  */
-
-static void
-remove_bb (basic_block bb)
-{
-  gimple_stmt_iterator i;
-  source_location loc = UNKNOWN_LOCATION;
-
-  if (dump_file)
-    {
-      fprintf (dump_file, "Removing basic block %d\n", bb->index);
-      if (dump_flags & TDF_DETAILS)
-       {
-         dump_bb (bb, dump_file, 0);
-         fprintf (dump_file, "\n");
-       }
-    }
-
-  if (current_loops)
-    {
-      struct loop *loop = bb->loop_father;
-
-      /* If a loop gets removed, clean up the information associated
-        with it.  */
-      if (loop->latch == bb
-         || loop->header == bb)
-       free_numbers_of_iterations_estimates_loop (loop);
-    }
-
-  /* Remove all the instructions in the block.  */
-  if (bb_seq (bb) != NULL)
-    {
-      /* Walk backwards so as to get a chance to substitute all
-        released DEFs into debug stmts.  See
-        eliminate_unnecessary_stmts() in tree-ssa-dce.c for more
-        details.  */
-      for (i = gsi_last_bb (bb); !gsi_end_p (i);)
-       {
-         gimple stmt = gsi_stmt (i);
-         if (gimple_code (stmt) == GIMPLE_LABEL
-             && (FORCED_LABEL (gimple_label_label (stmt))
-                 || DECL_NONLOCAL (gimple_label_label (stmt))))
-           {
-             basic_block new_bb;
-             gimple_stmt_iterator new_gsi;
-
-             /* A non-reachable non-local label may still be referenced.
-                But it no longer needs to carry the extra semantics of
-                non-locality.  */
-             if (DECL_NONLOCAL (gimple_label_label (stmt)))
-               {
-                 DECL_NONLOCAL (gimple_label_label (stmt)) = 0;
-                 FORCED_LABEL (gimple_label_label (stmt)) = 1;
-               }
-
-             new_bb = bb->prev_bb;
-             new_gsi = gsi_start_bb (new_bb);
-             gsi_remove (&i, false);
-             gsi_insert_before (&new_gsi, stmt, GSI_NEW_STMT);
-           }
-         else
-           {
-             /* Release SSA definitions if we are in SSA.  Note that we
-                may be called when not in SSA.  For example,
-                final_cleanup calls this function via
-                cleanup_tree_cfg.  */
-             if (gimple_in_ssa_p (cfun))
-               release_defs (stmt);
-
-             gsi_remove (&i, true);
-           }
-
-         if (gsi_end_p (i))
-           i = gsi_last_bb (bb);
-         else
-           gsi_prev (&i);
-
-         /* Don't warn for removed gotos.  Gotos are often removed due to
-            jump threading, thus resulting in bogus warnings.  Not great,
-            since this way we lose warnings for gotos in the original
-            program that are indeed unreachable.  */
-         if (gimple_code (stmt) != GIMPLE_GOTO
-             && gimple_has_location (stmt))
-           loc = gimple_location (stmt);
-       }
-    }
-
-  /* If requested, give a warning that the first statement in the
-     block is unreachable.  We walk statements backwards in the
-     loop above, so the last statement we process is the first statement
-     in the block.  */
-  if (loc > BUILTINS_LOCATION && LOCATION_LINE (loc) > 0)
-    warning_at (loc, OPT_Wunreachable_code, "will never be executed");
-
-  remove_phi_nodes_and_edges_for_unreachable_block (bb);
-  bb->il.gimple = NULL;
-}
-
-
-/* Given a basic block BB ending with COND_EXPR or SWITCH_EXPR, and a
-   predicate VAL, return the edge that will be taken out of the block.
-   If VAL does not match a unique edge, NULL is returned.  */
-
-edge
-find_taken_edge (basic_block bb, tree val)
-{
-  gimple stmt;
-
-  stmt = last_stmt (bb);
-
-  gcc_assert (stmt);
-  gcc_assert (is_ctrl_stmt (stmt));
-
-  if (val == NULL)
-    return NULL;
-
-  if (!is_gimple_min_invariant (val))
-    return NULL;
-
-  if (gimple_code (stmt) == GIMPLE_COND)
-    return find_taken_edge_cond_expr (bb, val);
-
-  if (gimple_code (stmt) == GIMPLE_SWITCH)
-    return find_taken_edge_switch_expr (bb, val);
-
-  if (computed_goto_p (stmt))
-    {
-      /* Only optimize if the argument is a label, if the argument is
-        not a label then we can not construct a proper CFG.
-
-         It may be the case that we only need to allow the LABEL_REF to
-         appear inside an ADDR_EXPR, but we also allow the LABEL_REF to
-         appear inside a LABEL_EXPR just to be safe.  */
-      if ((TREE_CODE (val) == ADDR_EXPR || TREE_CODE (val) == LABEL_EXPR)
-         && TREE_CODE (TREE_OPERAND (val, 0)) == LABEL_DECL)
-       return find_taken_edge_computed_goto (bb, TREE_OPERAND (val, 0));
-      return NULL;
-    }
-
-  gcc_unreachable ();
-}
-
-/* Given a constant value VAL and the entry block BB to a GOTO_EXPR
-   statement, determine which of the outgoing edges will be taken out of the
-   block.  Return NULL if either edge may be taken.  */
-
-static edge
-find_taken_edge_computed_goto (basic_block bb, tree val)
-{
-  basic_block dest;
-  edge e = NULL;
-
-  dest = label_to_block (val);
-  if (dest)
-    {
-      e = find_edge (bb, dest);
-      gcc_assert (e != NULL);
-    }
-
-  return e;
-}
-
-/* Given a constant value VAL and the entry block BB to a COND_EXPR
-   statement, determine which of the two edges will be taken out of the
-   block.  Return NULL if either edge may be taken.  */
-
-static edge
-find_taken_edge_cond_expr (basic_block bb, tree val)
-{
-  edge true_edge, false_edge;
+  edge true_edge, false_edge;
 
   extract_true_false_edges_from_block (bb, &true_edge, &false_edge);
 
@@ -2635,11 +2051,7 @@ gimple_dump_cfg (FILE *file, int flags)
 {
   if (flags & TDF_DETAILS)
     {
-      const char *funcname
-       = lang_hooks.decl_printable_name (current_function_decl, 2);
-
-      fputc ('\n', file);
-      fprintf (file, ";; Function %s\n\n", funcname);
+      dump_function_header (file, current_function_decl, flags);
       fprintf (file, ";; \n%d basic blocks, %d edges, last basic block %d.\n\n",
               n_basic_blocks, n_edges, last_basic_block);
 
@@ -2709,7 +2121,7 @@ dump_cfg_stats (FILE *file)
 /* Dump CFG statistics on stderr.  Keep extern so that it's always
    linked in the final executable.  */
 
-void
+DEBUG_FUNCTION void
 debug_cfg_stats (void)
 {
   dump_cfg_stats (stderr);
@@ -2841,11 +2253,16 @@ is_ctrl_altering_stmt (gimple t)
 
        /* A non-pure/const call alters flow control if the current
           function has nonlocal labels.  */
-       if (!(flags & (ECF_CONST | ECF_PURE)) && cfun->has_nonlocal_label)
+       if (!(flags & (ECF_CONST | ECF_PURE | ECF_LEAF))
+           && cfun->has_nonlocal_label)
          return true;
 
        /* A call also alters control flow if it does not return.  */
-       if (gimple_call_flags (t) & ECF_NORETURN)
+       if (flags & ECF_NORETURN)
+         return true;
+
+       /* BUILT_IN_RETURN call is same as return statement.  */
+       if (gimple_call_builtin_p (t, BUILT_IN_RETURN))
          return true;
       }
       break;
@@ -2893,7 +2310,8 @@ stmt_can_make_abnormal_goto (gimple t)
   if (computed_goto_p (t))
     return true;
   if (is_gimple_call (t))
-    return gimple_has_side_effects (t) && cfun->has_nonlocal_label;
+    return (gimple_has_side_effects (t) && cfun->has_nonlocal_label
+           && !(gimple_call_flags (t) & ECF_LEAF));
   return false;
 }
 
@@ -3038,11 +2456,11 @@ reinstall_phi_args (edge new_edge, edge old_edge)
   edge_var_map *vm;
   int i;
   gimple_stmt_iterator phis;
-  
+
   v = redirect_edge_var_map_vector (old_edge);
   if (!v)
     return;
-  
+
   for (i = 0, phis = gsi_start_phis (new_edge->dest);
        VEC_iterate (edge_var_map, v, i, vm) && !gsi_end_p (phis);
        i++, gsi_next (&phis))
@@ -3050,12 +2468,12 @@ reinstall_phi_args (edge new_edge, edge old_edge)
       gimple phi = gsi_stmt (phis);
       tree result = redirect_edge_var_map_result (vm);
       tree arg = redirect_edge_var_map_def (vm);
+
       gcc_assert (result == gimple_phi_result (phi));
-  
+
       add_phi_arg (phi, arg, new_edge, redirect_edge_var_map_location (vm));
     }
-  
+
   redirect_edge_var_map_clear (old_edge);
 }
 
@@ -3109,6 +2527,49 @@ gimple_split_edge (edge edge_in)
   return new_bb;
 }
 
+
+/* Verify properties of the address expression T with base object BASE.  */
+
+static tree
+verify_address (tree t, tree base)
+{
+  bool old_constant;
+  bool old_side_effects;
+  bool new_constant;
+  bool new_side_effects;
+
+  old_constant = TREE_CONSTANT (t);
+  old_side_effects = TREE_SIDE_EFFECTS (t);
+
+  recompute_tree_invariant_for_addr_expr (t);
+  new_side_effects = TREE_SIDE_EFFECTS (t);
+  new_constant = TREE_CONSTANT (t);
+
+  if (old_constant != new_constant)
+    {
+      error ("constant not recomputed when ADDR_EXPR changed");
+      return t;
+    }
+  if (old_side_effects != new_side_effects)
+    {
+      error ("side effects not recomputed when ADDR_EXPR changed");
+      return t;
+    }
+
+  if (!(TREE_CODE (base) == VAR_DECL
+       || TREE_CODE (base) == PARM_DECL
+       || TREE_CODE (base) == RESULT_DECL))
+    return NULL_TREE;
+
+  if (DECL_GIMPLE_REG_P (base))
+    {
+      error ("DECL_GIMPLE_REG_P set on a variable with address taken");
+      return base;
+    }
+
+  return NULL_TREE;
+}
+
 /* Callback for walk_tree, check that all elements with address taken are
    properly noticed as such.  The DATA is an int* that is 1 if TP was seen
    inside a PHI node.  */
@@ -3137,12 +2598,27 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
       break;
 
     case INDIRECT_REF:
+      error ("INDIRECT_REF in gimple IL");
+      return t;
+
+    case MEM_REF:
       x = TREE_OPERAND (t, 0);
-      if (!is_gimple_reg (x) && !is_gimple_min_invariant (x))
+      if (!POINTER_TYPE_P (TREE_TYPE (x))
+         || !is_gimple_mem_ref_addr (x))
        {
-         error ("Indirect reference's operand is not a register or a constant.");
+         error ("invalid first operand of MEM_REF");
          return x;
        }
+      if (TREE_CODE (TREE_OPERAND (t, 1)) != INTEGER_CST
+         || !POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (t, 1))))
+       {
+         error ("invalid offset operand of MEM_REF");
+         return TREE_OPERAND (t, 1);
+       }
+      if (TREE_CODE (x) == ADDR_EXPR
+         && (x = verify_address (x, TREE_OPERAND (x, 0))))
+       return x;
+      *walk_subtrees = 0;
       break;
 
     case ASSERT_EXPR:
@@ -3155,36 +2631,15 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
       break;
 
     case MODIFY_EXPR:
-      error ("MODIFY_EXPR not expected while having tuples.");
+      error ("MODIFY_EXPR not expected while having tuples");
       return *tp;
 
     case ADDR_EXPR:
       {
-       bool old_constant;
-       bool old_side_effects;
-       bool new_constant;
-       bool new_side_effects;
+       tree tem;
 
        gcc_assert (is_gimple_address (t));
 
-       old_constant = TREE_CONSTANT (t);
-       old_side_effects = TREE_SIDE_EFFECTS (t);
-
-       recompute_tree_invariant_for_addr_expr (t);
-       new_side_effects = TREE_SIDE_EFFECTS (t);
-       new_constant = TREE_CONSTANT (t);
-
-        if (old_constant != new_constant)
-         {
-           error ("constant not recomputed when ADDR_EXPR changed");
-           return t;
-         }
-       if (old_side_effects != new_side_effects)
-         {
-           error ("side effects not recomputed when ADDR_EXPR changed");
-           return t;
-         }
-
        /* Skip any references (they will be checked when we recurse down the
           tree) and ensure that any variable used as a prefix is marked
           addressable.  */
@@ -3193,20 +2648,19 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
             x = TREE_OPERAND (x, 0))
          ;
 
+       if ((tem = verify_address (t, x)))
+         return tem;
+
        if (!(TREE_CODE (x) == VAR_DECL
              || TREE_CODE (x) == PARM_DECL
              || TREE_CODE (x) == RESULT_DECL))
          return NULL;
+
        if (!TREE_ADDRESSABLE (x))
          {
            error ("address taken, but ADDRESSABLE bit not set");
            return x;
          }
-       if (DECL_GIMPLE_REG_P (x))
-         {
-           error ("DECL_GIMPLE_REG_P set on a variable with address taken");
-           return x;
-         }
 
        break;
       }
@@ -3226,7 +2680,8 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
       break;
 
     case NON_LVALUE_EXPR:
-       gcc_unreachable ();
+    case TRUTH_NOT_EXPR:
+      gcc_unreachable ();
 
     CASE_CONVERT:
     case FIX_TRUNC_EXPR:
@@ -3234,7 +2689,6 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
     case NEGATE_EXPR:
     case ABS_EXPR:
     case BIT_NOT_EXPR:
-    case TRUTH_NOT_EXPR:
       CHECK_OP (0, "invalid operand to unary operator");
       break;
 
@@ -3324,7 +2778,7 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
                                     TREE_TYPE (TREE_OPERAND (t, 1))))
        {
          error ("invalid operand to pointer plus, second operand is not an "
-                "integer with type of sizetype.");
+                "integer with type of sizetype");
          return t;
        }
       /* FALLTHROUGH */
@@ -3371,6 +2825,14 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
        *walk_subtrees = 0;
       break;
 
+    case CASE_LABEL_EXPR:
+      if (CASE_CHAIN (t))
+       {
+         error ("invalid CASE_CHAIN");
+         return t;
+       }
+      break;
+
     default:
       break;
     }
@@ -3391,8 +2853,8 @@ verify_types_in_gimple_min_lval (tree expr)
   if (is_gimple_id (expr))
     return false;
 
-  if (!INDIRECT_REF_P (expr)
-      && TREE_CODE (expr) != TARGET_MEM_REF)
+  if (TREE_CODE (expr) != TARGET_MEM_REF
+      && TREE_CODE (expr) != MEM_REF)
     {
       error ("invalid expression for min lvalue");
       return true;
@@ -3409,14 +2871,7 @@ verify_types_in_gimple_min_lval (tree expr)
       debug_generic_stmt (op);
       return true;
     }
-  if (!useless_type_conversion_p (TREE_TYPE (expr),
-                                 TREE_TYPE (TREE_TYPE (op))))
-    {
-      error ("type mismatch in indirect reference");
-      debug_generic_stmt (TREE_TYPE (expr));
-      debug_generic_stmt (TREE_TYPE (TREE_TYPE (op)));
-      return true;
-    }
+  /* Memory references now generally can involve a value conversion.  */
 
   return false;
 }
@@ -3488,16 +2943,69 @@ verify_types_in_gimple_reference (tree expr, bool require_lvalue)
          return true;
        }
 
-      /* For VIEW_CONVERT_EXPRs which are allowed here, too, there
-        is nothing to verify.  Gross mismatches at most invoke
-        undefined behavior.  */
-      if (TREE_CODE (expr) == VIEW_CONVERT_EXPR
-         && !handled_component_p (op))
-       return false;
+      if (TREE_CODE (expr) == VIEW_CONVERT_EXPR)
+       {
+         /* For VIEW_CONVERT_EXPRs which are allowed here too, we only check
+            that their operand is not an SSA name or an invariant when
+            requiring an lvalue (this usually means there is a SRA or IPA-SRA
+            bug).  Otherwise there is nothing to verify, gross mismatches at
+            most invoke undefined behavior.  */
+         if (require_lvalue
+             && (TREE_CODE (op) == SSA_NAME
+                 || is_gimple_min_invariant (op)))
+           {
+             error ("conversion of an SSA_NAME on the left hand side");
+             debug_generic_stmt (expr);
+             return true;
+           }
+         else if (TREE_CODE (op) == SSA_NAME
+                  && TYPE_SIZE (TREE_TYPE (expr)) != TYPE_SIZE (TREE_TYPE (op)))
+           {
+             error ("conversion of register to a different size");
+             debug_generic_stmt (expr);
+             return true;
+           }
+         else if (!handled_component_p (op))
+           return false;
+       }
 
       expr = op;
     }
 
+  if (TREE_CODE (expr) == MEM_REF)
+    {
+      if (!is_gimple_mem_ref_addr (TREE_OPERAND (expr, 0)))
+       {
+         error ("invalid address operand in MEM_REF");
+         debug_generic_stmt (expr);
+         return true;
+       }
+      if (TREE_CODE (TREE_OPERAND (expr, 1)) != INTEGER_CST
+         || !POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 1))))
+       {
+         error ("invalid offset operand in MEM_REF");
+         debug_generic_stmt (expr);
+         return true;
+       }
+    }
+  else if (TREE_CODE (expr) == TARGET_MEM_REF)
+    {
+      if (!TMR_BASE (expr)
+         || !is_gimple_mem_ref_addr (TMR_BASE (expr)))
+       {
+         error ("invalid address operand in TARGET_MEM_REF");
+         return true;
+       }
+      if (!TMR_OFFSET (expr)
+         || TREE_CODE (TMR_OFFSET (expr)) != INTEGER_CST
+         || !POINTER_TYPE_P (TREE_TYPE (TMR_OFFSET (expr))))
+       {
+         error ("invalid offset operand in TARGET_MEM_REF");
+         debug_generic_stmt (expr);
+         return true;
+       }
+    }
+
   return ((require_lvalue || !is_gimple_min_invariant (expr))
          && verify_types_in_gimple_min_lval (expr));
 }
@@ -3539,25 +3047,71 @@ static bool
 verify_gimple_call (gimple stmt)
 {
   tree fn = gimple_call_fn (stmt);
-  tree fntype;
+  tree fntype, fndecl;
+  unsigned i;
+
+  if (gimple_call_internal_p (stmt))
+    {
+      if (fn)
+       {
+         error ("gimple call has two targets");
+         debug_generic_stmt (fn);
+         return true;
+       }
+    }
+  else
+    {
+      if (!fn)
+       {
+         error ("gimple call has no target");
+         return true;
+       }
+    }
+
+  if (fn && !is_gimple_call_addr (fn))
+    {
+      error ("invalid function in gimple call");
+      debug_generic_stmt (fn);
+      return true;
+    }
 
-  if (!POINTER_TYPE_P (TREE_TYPE  (fn))
-      || (TREE_CODE (TREE_TYPE (TREE_TYPE (fn))) != FUNCTION_TYPE
-         && TREE_CODE (TREE_TYPE (TREE_TYPE (fn))) != METHOD_TYPE))
+  if (fn
+      && (!POINTER_TYPE_P (TREE_TYPE (fn))
+         || (TREE_CODE (TREE_TYPE (TREE_TYPE (fn))) != FUNCTION_TYPE
+             && TREE_CODE (TREE_TYPE (TREE_TYPE (fn))) != METHOD_TYPE)))
     {
       error ("non-function in gimple call");
       return true;
     }
 
+   fndecl = gimple_call_fndecl (stmt);
+   if (fndecl
+       && TREE_CODE (fndecl) == FUNCTION_DECL
+       && DECL_LOOPING_CONST_OR_PURE_P (fndecl)
+       && !DECL_PURE_P (fndecl)
+       && !TREE_READONLY (fndecl))
+     {
+       error ("invalid pure const state for function");
+       return true;
+     }
+
   if (gimple_call_lhs (stmt)
-      && !is_gimple_lvalue (gimple_call_lhs (stmt)))
+      && (!is_gimple_lvalue (gimple_call_lhs (stmt))
+         || verify_types_in_gimple_reference (gimple_call_lhs (stmt), true)))
     {
       error ("invalid LHS in gimple call");
       return true;
     }
 
-  fntype = TREE_TYPE (TREE_TYPE (fn));
-  if (gimple_call_lhs (stmt)
+  if (gimple_call_lhs (stmt) && gimple_call_noreturn_p (stmt))
+    {
+      error ("LHS in noreturn call");
+      return true;
+    }
+
+  fntype = gimple_call_fntype (stmt);
+  if (fntype
+      && gimple_call_lhs (stmt)
       && !useless_type_conversion_p (TREE_TYPE (gimple_call_lhs (stmt)),
                                     TREE_TYPE (fntype))
       /* ???  At least C++ misses conversions at assignments from
@@ -3574,12 +3128,19 @@ verify_gimple_call (gimple stmt)
       return true;
     }
 
+  if (gimple_call_chain (stmt)
+      && !is_gimple_val (gimple_call_chain (stmt)))
+    {
+      error ("invalid static chain in gimple call");
+      debug_generic_stmt (gimple_call_chain (stmt));
+      return true;
+    }
+
   /* If there is a static chain argument, this should not be an indirect
      call, and the decl should have DECL_STATIC_CHAIN set.  */
   if (gimple_call_chain (stmt))
     {
-      if (TREE_CODE (fn) != ADDR_EXPR
-         || TREE_CODE (TREE_OPERAND (fn, 0)) != FUNCTION_DECL)
+      if (!gimple_call_fndecl (stmt))
        {
          error ("static chain in indirect gimple call");
          return true;
@@ -3588,16 +3149,30 @@ verify_gimple_call (gimple stmt)
 
       if (!DECL_STATIC_CHAIN (fn))
        {
-         error ("static chain with function that doesn't use one");
+         error ("static chain with function that doesn%'t use one");
          return true;
        }
     }
 
   /* ???  The C frontend passes unpromoted arguments in case it
      didn't see a function declaration before the call.  So for now
-     leave the call arguments unverified.  Once we gimplify
+     leave the call arguments mostly unverified.  Once we gimplify
      unit-at-a-time we have a chance to fix this.  */
 
+  for (i = 0; i < gimple_call_num_args (stmt); ++i)
+    {
+      tree arg = gimple_call_arg (stmt, i);
+      if ((is_gimple_reg_type (TREE_TYPE (arg))
+          && !is_gimple_val (arg))
+         || (!is_gimple_reg_type (TREE_TYPE (arg))
+             && !is_gimple_lvalue (arg)))
+       {
+         error ("invalid argument to gimple call");
+         debug_generic_expr (arg);
+         return true;
+       }
+    }
+
   return false;
 }
 
@@ -3628,7 +3203,9 @@ verify_gimple_comparison (tree type, tree op0, tree op1)
        && (!POINTER_TYPE_P (op0_type)
           || !POINTER_TYPE_P (op1_type)
           || TYPE_MODE (op0_type) != TYPE_MODE (op1_type)))
-      || !INTEGRAL_TYPE_P (type))
+      || !INTEGRAL_TYPE_P (type)
+      || (TREE_CODE (type) != BOOLEAN_TYPE
+         && TYPE_PRECISION (type) != 1))
     {
       error ("type mismatch in comparison expression");
       debug_generic_expr (type);
@@ -3652,9 +3229,7 @@ verify_gimple_assign_unary (gimple stmt)
   tree rhs1 = gimple_assign_rhs1 (stmt);
   tree rhs1_type = TREE_TYPE (rhs1);
 
-  if (!is_gimple_reg (lhs)
-      && !(optimize == 0
-          && TREE_CODE (lhs_type) == COMPLEX_TYPE))
+  if (!is_gimple_reg (lhs))
     {
       error ("non-register as LHS of unary operation");
       return true;
@@ -3706,6 +3281,21 @@ verify_gimple_assign_unary (gimple stmt)
        return false;
       }
 
+    case ADDR_SPACE_CONVERT_EXPR:
+      {
+       if (!POINTER_TYPE_P (rhs1_type) || !POINTER_TYPE_P (lhs_type)
+           || (TYPE_ADDR_SPACE (TREE_TYPE (rhs1_type))
+               == TYPE_ADDR_SPACE (TREE_TYPE (lhs_type))))
+         {
+           error ("invalid types in address space conversion");
+           debug_generic_expr (lhs_type);
+           debug_generic_expr (rhs1_type);
+           return true;
+         }
+
+       return false;
+      }
+
     case FIXED_CONVERT_EXPR:
       {
        if (!valid_fixed_convert_types_p (lhs_type, rhs1_type)
@@ -3756,7 +3346,6 @@ verify_gimple_assign_unary (gimple stmt)
       /* FIXME.  */
       return false;
 
-    case TRUTH_NOT_EXPR:
     case NEGATE_EXPR:
     case ABS_EXPR:
     case BIT_NOT_EXPR:
@@ -3795,9 +3384,7 @@ verify_gimple_assign_binary (gimple stmt)
   tree rhs2 = gimple_assign_rhs2 (stmt);
   tree rhs2_type = TREE_TYPE (rhs2);
 
-  if (!is_gimple_reg (lhs)
-      && !(optimize == 0
-          && TREE_CODE (lhs_type) == COMPLEX_TYPE))
+  if (!is_gimple_reg (lhs))
     {
       error ("non-register as LHS of binary operation");
       return true;
@@ -3841,13 +3428,13 @@ verify_gimple_assign_binary (gimple stmt)
        if ((!INTEGRAL_TYPE_P (rhs1_type)
             && !FIXED_POINT_TYPE_P (rhs1_type)
             && !(TREE_CODE (rhs1_type) == VECTOR_TYPE
-                 && TREE_CODE (TREE_TYPE (rhs1_type)) == INTEGER_TYPE))
+                 && INTEGRAL_TYPE_P (TREE_TYPE (rhs1_type))))
            || (!INTEGRAL_TYPE_P (rhs2_type)
                /* Vector shifts of vectors are also ok.  */
                && !(TREE_CODE (rhs1_type) == VECTOR_TYPE
-                    && TREE_CODE (TREE_TYPE (rhs1_type)) == INTEGER_TYPE
+                    && INTEGRAL_TYPE_P (TREE_TYPE (rhs1_type))
                     && TREE_CODE (rhs2_type) == VECTOR_TYPE
-                    && TREE_CODE (TREE_TYPE (rhs2_type)) == INTEGER_TYPE))
+                    && INTEGRAL_TYPE_P (TREE_TYPE (rhs2_type))))
            || !useless_type_conversion_p (lhs_type, rhs1_type))
          {
            error ("type mismatch in shift expression");
@@ -3865,6 +3452,7 @@ verify_gimple_assign_binary (gimple stmt)
       {
        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)
@@ -3878,9 +3466,9 @@ verify_gimple_assign_binary (gimple stmt)
            debug_generic_expr (rhs2_type);
            return true;
          }
-       /* For shifting a vector of floating point components we
+       /* For shifting a vector of non-integral components we
           only allow shifting by a constant multiple of the element size.  */
-       if (SCALAR_FLOAT_TYPE_P (TREE_TYPE (rhs1_type))
+       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)))))
@@ -3893,8 +3481,9 @@ verify_gimple_assign_binary (gimple stmt)
       }
 
     case PLUS_EXPR:
+    case MINUS_EXPR:
       {
-       /* We use regular PLUS_EXPR for vectors.
+       /* We use regular PLUS_EXPR and MINUS_EXPR for vectors.
           ???  This just makes the checker happy and may not be what is
           intended.  */
        if (TREE_CODE (lhs_type) == VECTOR_TYPE
@@ -3919,10 +3508,6 @@ verify_gimple_assign_binary (gimple stmt)
              }
            goto do_pointer_plus_expr_check;
          }
-      }
-    /* Fallthru.  */
-    case MINUS_EXPR:
-      {
        if (POINTER_TYPE_P (lhs_type)
            || POINTER_TYPE_P (rhs1_type)
            || POINTER_TYPE_P (rhs2_type))
@@ -3950,30 +3535,15 @@ do_pointer_plus_expr_check:
          }
 
        return false;
-      } 
+      }
 
     case TRUTH_ANDIF_EXPR:
     case TRUTH_ORIF_EXPR:
-      gcc_unreachable ();
-
     case TRUTH_AND_EXPR:
     case TRUTH_OR_EXPR:
     case TRUTH_XOR_EXPR:
-      {
-       /* We allow any kind of integral typed argument and result.  */
-       if (!INTEGRAL_TYPE_P (rhs1_type)
-           || !INTEGRAL_TYPE_P (rhs2_type)
-           || !INTEGRAL_TYPE_P (lhs_type))
-         {
-           error ("type mismatch in binary truth expression");
-           debug_generic_expr (lhs_type);
-           debug_generic_expr (rhs1_type);
-           debug_generic_expr (rhs2_type);
-           return true;
-         }
 
-       return false;
-      }
+      gcc_unreachable ();
 
     case LT_EXPR:
     case LE_EXPR:
@@ -3993,8 +3563,13 @@ do_pointer_plus_expr_check:
         connected to the operand types.  */
       return verify_gimple_comparison (lhs_type, rhs1, rhs2);
 
-    case WIDEN_SUM_EXPR:
     case WIDEN_MULT_EXPR:
+      if (TREE_CODE (lhs_type) != INTEGER_TYPE)
+       return true;
+      return ((2 * TYPE_PRECISION (rhs1_type) != TYPE_PRECISION (lhs_type))
+             || (TYPE_PRECISION (rhs1_type) != TYPE_PRECISION (rhs2_type)));
+
+    case WIDEN_SUM_EXPR:
     case VEC_WIDEN_MULT_HI_EXPR:
     case VEC_WIDEN_MULT_LO_EXPR:
     case VEC_PACK_TRUNC_EXPR:
@@ -4043,6 +3618,82 @@ do_pointer_plus_expr_check:
   return false;
 }
 
+/* Verify a gimple assignment statement STMT with a ternary rhs.
+   Returns true if anything is wrong.  */
+
+static bool
+verify_gimple_assign_ternary (gimple stmt)
+{
+  enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
+  tree lhs = gimple_assign_lhs (stmt);
+  tree lhs_type = TREE_TYPE (lhs);
+  tree rhs1 = gimple_assign_rhs1 (stmt);
+  tree rhs1_type = TREE_TYPE (rhs1);
+  tree rhs2 = gimple_assign_rhs2 (stmt);
+  tree rhs2_type = TREE_TYPE (rhs2);
+  tree rhs3 = gimple_assign_rhs3 (stmt);
+  tree rhs3_type = TREE_TYPE (rhs3);
+
+  if (!is_gimple_reg (lhs))
+    {
+      error ("non-register as LHS of ternary operation");
+      return true;
+    }
+
+  if (!is_gimple_val (rhs1)
+      || !is_gimple_val (rhs2)
+      || !is_gimple_val (rhs3))
+    {
+      error ("invalid operands in ternary operation");
+      return true;
+    }
+
+  /* First handle operations that involve different types.  */
+  switch (rhs_code)
+    {
+    case WIDEN_MULT_PLUS_EXPR:
+    case WIDEN_MULT_MINUS_EXPR:
+      if ((!INTEGRAL_TYPE_P (rhs1_type)
+          && !FIXED_POINT_TYPE_P (rhs1_type))
+         || !useless_type_conversion_p (rhs1_type, rhs2_type)
+         || !useless_type_conversion_p (lhs_type, rhs3_type)
+         || 2 * TYPE_PRECISION (rhs1_type) != TYPE_PRECISION (lhs_type)
+         || TYPE_PRECISION (rhs1_type) != TYPE_PRECISION (rhs2_type))
+       {
+         error ("type mismatch in widening multiply-accumulate expression");
+         debug_generic_expr (lhs_type);
+         debug_generic_expr (rhs1_type);
+         debug_generic_expr (rhs2_type);
+         debug_generic_expr (rhs3_type);
+         return true;
+       }
+      break;
+
+    case FMA_EXPR:
+      if (!useless_type_conversion_p (lhs_type, rhs1_type)
+         || !useless_type_conversion_p (lhs_type, rhs2_type)
+         || !useless_type_conversion_p (lhs_type, rhs3_type))
+       {
+         error ("type mismatch in fused multiply-add expression");
+         debug_generic_expr (lhs_type);
+         debug_generic_expr (rhs1_type);
+         debug_generic_expr (rhs2_type);
+         debug_generic_expr (rhs3_type);
+         return true;
+       }
+      break;
+
+    case DOT_PROD_EXPR:
+    case REALIGN_LOAD_EXPR:
+      /* FIXME.  */
+      return false;
+
+    default:
+      gcc_unreachable ();
+    }
+  return false;
+}
+
 /* Verify a gimple assignment statement STMT with a single rhs.
    Returns true if anything is wrong.  */
 
@@ -4079,7 +3730,13 @@ verify_gimple_assign_single (gimple stmt)
            return true;
          }
 
-       if (!types_compatible_p (TREE_TYPE (op), TREE_TYPE (TREE_TYPE (rhs1)))
+       /* Technically there is no longer a need for matching types, but
+          gimple hygiene asks for this check.  In LTO we can end up
+          combining incompatible units and thus end up with addresses
+          of globals that change their type to a common one.  */
+       if (!in_lto_p
+           && !types_compatible_p (TREE_TYPE (op),
+                                   TREE_TYPE (TREE_TYPE (rhs1)))
            && !one_pointer_to_useless_type_conversion_p (TREE_TYPE (rhs1),
                                                          TREE_TYPE (op)))
          {
@@ -4093,17 +3750,19 @@ verify_gimple_assign_single (gimple stmt)
       }
 
     /* tcc_reference  */
+    case INDIRECT_REF:
+      error ("INDIRECT_REF in gimple IL");
+      return true;
+
     case COMPONENT_REF:
     case BIT_FIELD_REF:
-    case INDIRECT_REF:
-    case ALIGN_INDIRECT_REF:
-    case MISALIGNED_INDIRECT_REF:
     case ARRAY_REF:
     case ARRAY_RANGE_REF:
     case VIEW_CONVERT_EXPR:
     case REALPART_EXPR:
     case IMAGPART_EXPR:
     case TARGET_MEM_REF:
+    case MEM_REF:
       if (!is_gimple_reg (lhs)
          && is_gimple_reg_type (TREE_TYPE (lhs)))
        {
@@ -4141,14 +3800,25 @@ verify_gimple_assign_single (gimple stmt)
       return res;
 
     case COND_EXPR:
+      if (!is_gimple_reg (lhs)
+         || (!is_gimple_reg (TREE_OPERAND (rhs1, 0))
+             && !COMPARISON_CLASS_P (TREE_OPERAND (rhs1, 0)))
+         || (!is_gimple_reg (TREE_OPERAND (rhs1, 1))
+             && !is_gimple_min_invariant (TREE_OPERAND (rhs1, 1)))
+         || (!is_gimple_reg (TREE_OPERAND (rhs1, 2))
+             && !is_gimple_min_invariant (TREE_OPERAND (rhs1, 2))))
+       {
+         error ("invalid COND_EXPR in gimple assignment");
+         debug_generic_stmt (rhs1);
+         return true;
+       }
+      return res;
+
     case CONSTRUCTOR:
     case OBJ_TYPE_REF:
     case ASSERT_EXPR:
     case WITH_SIZE_EXPR:
-    case POLYNOMIAL_CHREC:
-    case DOT_PROD_EXPR:
     case VEC_COND_EXPR:
-    case REALIGN_LOAD_EXPR:
       /* FIXME.  */
       return res;
 
@@ -4175,6 +3845,9 @@ verify_gimple_assign (gimple stmt)
     case GIMPLE_BINARY_RHS:
       return verify_gimple_assign_binary (stmt);
 
+    case GIMPLE_TERNARY_RHS:
+      return verify_gimple_assign_ternary (stmt);
+
     default:
       gcc_unreachable ();
     }
@@ -4193,7 +3866,7 @@ verify_gimple_return (gimple stmt)
      return values from the original source.  */
   if (op == NULL)
     return false;
+
   if (!is_gimple_val (op)
       && TREE_CODE (op) != RESULT_DECL)
     {
@@ -4202,12 +3875,14 @@ verify_gimple_return (gimple stmt)
       return true;
     }
 
-  if (!useless_type_conversion_p (restype, TREE_TYPE (op))
-      /* ???  With C++ we can have the situation that the result
-        decl is a reference type while the return type is an aggregate.  */
-      && !(TREE_CODE (op) == RESULT_DECL
-          && TREE_CODE (TREE_TYPE (op)) == REFERENCE_TYPE
-          && useless_type_conversion_p (restype, TREE_TYPE (TREE_TYPE (op)))))
+  if ((TREE_CODE (op) == RESULT_DECL
+       && DECL_BY_REFERENCE (op))
+      || (TREE_CODE (op) == SSA_NAME
+         && TREE_CODE (SSA_NAME_VAR (op)) == RESULT_DECL
+         && DECL_BY_REFERENCE (SSA_NAME_VAR (op))))
+    op = TREE_TYPE (op);
+
+  if (!useless_type_conversion_p (restype, TREE_TYPE (op)))
     {
       error ("invalid conversion in return statement");
       debug_generic_stmt (restype);
@@ -4257,46 +3932,6 @@ verify_gimple_switch (gimple stmt)
 }
 
 
-/* Verify the contents of a GIMPLE_PHI.  Returns true if there is a problem,
-   and false otherwise.  */
-
-static bool
-verify_gimple_phi (gimple stmt)
-{
-  tree type = TREE_TYPE (gimple_phi_result (stmt));
-  unsigned i;
-
-  if (TREE_CODE (gimple_phi_result (stmt)) != SSA_NAME)
-    {
-      error ("Invalid PHI result");
-      return true;
-    }
-
-  for (i = 0; i < gimple_phi_num_args (stmt); i++)
-    {
-      tree arg = gimple_phi_arg_def (stmt, i);
-      if ((is_gimple_reg (gimple_phi_result (stmt))
-          && !is_gimple_val (arg))
-         || (!is_gimple_reg (gimple_phi_result (stmt))
-             && !is_gimple_addressable (arg)))
-       {
-         error ("Invalid PHI argument");
-         debug_generic_stmt (arg);
-         return true;
-       }
-      if (!useless_type_conversion_p (type, TREE_TYPE (arg)))
-       {
-         error ("Incompatible types in PHI argument %u", i);
-         debug_generic_stmt (type);
-         debug_generic_stmt (TREE_TYPE (arg));
-         return true;
-       }
-    }
-
-  return false;
-}
-
-
 /* Verify a gimple debug statement STMT.
    Returns true if anything is wrong.  */
 
@@ -4312,12 +3947,48 @@ verify_gimple_debug (gimple stmt ATTRIBUTE_UNUSED)
   return false;
 }
 
+/* Verify a gimple label statement STMT.
+   Returns true if anything is wrong.  */
+
+static bool
+verify_gimple_label (gimple stmt)
+{
+  tree decl = gimple_label_label (stmt);
+  int uid;
+  bool err = false;
+
+  if (TREE_CODE (decl) != LABEL_DECL)
+    return true;
+
+  uid = LABEL_DECL_UID (decl);
+  if (cfun->cfg
+      && (uid == -1
+         || VEC_index (basic_block,
+                       label_to_block_map, uid) != gimple_bb (stmt)))
+    {
+      error ("incorrect entry in label_to_block_map");
+      err |= true;
+    }
+
+  uid = EH_LANDING_PAD_NR (decl);
+  if (uid)
+    {
+      eh_landing_pad lp = get_eh_landing_pad_from_number (uid);
+      if (decl != lp->post_landing_pad)
+       {
+         error ("incorrect setting of landing pad number");
+         err |= true;
+       }
+    }
+
+  return err;
+}
 
 /* Verify the GIMPLE statement STMT.  Returns true if there is an
    error, otherwise false.  */
 
 static bool
-verify_types_in_gimple_stmt (gimple stmt)
+verify_gimple_stmt (gimple stmt)
 {
   switch (gimple_code (stmt))
     {
@@ -4325,12 +3996,26 @@ verify_types_in_gimple_stmt (gimple stmt)
       return verify_gimple_assign (stmt);
 
     case GIMPLE_LABEL:
-      return TREE_CODE (gimple_label_label (stmt)) != LABEL_DECL;
+      return verify_gimple_label (stmt);
 
     case GIMPLE_CALL:
       return verify_gimple_call (stmt);
 
     case GIMPLE_COND:
+      if (TREE_CODE_CLASS (gimple_cond_code (stmt)) != tcc_comparison)
+       {
+         error ("invalid comparison code in gimple cond");
+         return true;
+       }
+      if (!(!gimple_cond_true_label (stmt)
+           || TREE_CODE (gimple_cond_true_label (stmt)) == LABEL_DECL)
+         || !(!gimple_cond_false_label (stmt)
+              || TREE_CODE (gimple_cond_false_label (stmt)) == LABEL_DECL))
+       {
+         error ("invalid labels in gimple cond");
+         return true;
+       }
+         
       return verify_gimple_comparison (boolean_type_node,
                                       gimple_cond_lhs (stmt),
                                       gimple_cond_rhs (stmt));
@@ -4347,9 +4032,6 @@ verify_types_in_gimple_stmt (gimple stmt)
     case GIMPLE_ASM:
       return false;
 
-    case GIMPLE_PHI:
-      return verify_gimple_phi (stmt);
-
     /* Tuples that do not have tree operands.  */
     case GIMPLE_NOP:
     case GIMPLE_PREDICT:
@@ -4375,10 +4057,74 @@ verify_types_in_gimple_stmt (gimple stmt)
     }
 }
 
+/* Verify the contents of a GIMPLE_PHI.  Returns true if there is a problem,
+   and false otherwise.  */
+
+static bool
+verify_gimple_phi (gimple phi)
+{
+  bool err = false;
+  unsigned i;
+  tree phi_result = gimple_phi_result (phi);
+  bool virtual_p;
+
+  if (!phi_result)
+    {
+      error ("invalid PHI result");
+      return true;
+    }
+
+  virtual_p = !is_gimple_reg (phi_result);
+  if (TREE_CODE (phi_result) != SSA_NAME
+      || (virtual_p
+         && SSA_NAME_VAR (phi_result) != gimple_vop (cfun)))
+    {
+      error ("invalid PHI result");
+      err = true;
+    }
+
+  for (i = 0; i < gimple_phi_num_args (phi); i++)
+    {
+      tree t = gimple_phi_arg_def (phi, i);
+
+      if (!t)
+       {
+         error ("missing PHI def");
+         err |= true;
+         continue;
+       }
+      /* Addressable variables do have SSA_NAMEs but they
+        are not considered gimple values.  */
+      else if ((TREE_CODE (t) == SSA_NAME
+               && virtual_p != !is_gimple_reg (t))
+              || (virtual_p
+                  && (TREE_CODE (t) != SSA_NAME
+                      || SSA_NAME_VAR (t) != gimple_vop (cfun)))
+              || (!virtual_p
+                  && !is_gimple_val (t)))
+       {
+         error ("invalid PHI argument");
+         debug_generic_expr (t);
+         err |= true;
+       }
+#ifdef ENABLE_TYPES_CHECKING
+      if (!useless_type_conversion_p (TREE_TYPE (phi_result), TREE_TYPE (t)))
+       {
+         error ("incompatible types in PHI argument %u", i);
+         debug_generic_stmt (TREE_TYPE (phi_result));
+         debug_generic_stmt (TREE_TYPE (t));
+         err |= true;
+       }
+#endif
+    }
+
+  return err;
+}
+
 /* Verify the GIMPLE statements inside the sequence STMTS.  */
 
 static bool
-verify_types_in_gimple_seq_2 (gimple_seq stmts)
+verify_gimple_in_seq_2 (gimple_seq stmts)
 {
   gimple_stmt_iterator ittr;
   bool err = false;
@@ -4390,25 +4136,25 @@ verify_types_in_gimple_seq_2 (gimple_seq stmts)
       switch (gimple_code (stmt))
         {
        case GIMPLE_BIND:
-         err |= verify_types_in_gimple_seq_2 (gimple_bind_body (stmt));
+         err |= verify_gimple_in_seq_2 (gimple_bind_body (stmt));
          break;
 
        case GIMPLE_TRY:
-         err |= verify_types_in_gimple_seq_2 (gimple_try_eval (stmt));
-         err |= verify_types_in_gimple_seq_2 (gimple_try_cleanup (stmt));
+         err |= verify_gimple_in_seq_2 (gimple_try_eval (stmt));
+         err |= verify_gimple_in_seq_2 (gimple_try_cleanup (stmt));
          break;
 
        case GIMPLE_EH_FILTER:
-         err |= verify_types_in_gimple_seq_2 (gimple_eh_filter_failure (stmt));
+         err |= verify_gimple_in_seq_2 (gimple_eh_filter_failure (stmt));
          break;
 
        case GIMPLE_CATCH:
-         err |= verify_types_in_gimple_seq_2 (gimple_catch_handler (stmt));
+         err |= verify_gimple_in_seq_2 (gimple_catch_handler (stmt));
          break;
 
        default:
          {
-           bool err2 = verify_types_in_gimple_stmt (stmt);
+           bool err2 = verify_gimple_stmt (stmt);
            if (err2)
              debug_gimple_stmt (stmt);
            err |= err2;
@@ -4422,108 +4168,15 @@ verify_types_in_gimple_seq_2 (gimple_seq stmts)
 
 /* Verify the GIMPLE statements inside the statement list STMTS.  */
 
-void
-verify_types_in_gimple_seq (gimple_seq stmts)
+DEBUG_FUNCTION void
+verify_gimple_in_seq (gimple_seq stmts)
 {
-  if (verify_types_in_gimple_seq_2 (stmts))
+  timevar_push (TV_TREE_STMT_VERIFY);
+  if (verify_gimple_in_seq_2 (stmts))
     internal_error ("verify_gimple failed");
+  timevar_pop (TV_TREE_STMT_VERIFY);
 }
 
-
-/* Verify STMT, return true if STMT is not in GIMPLE form.
-   TODO: Implement type checking.  */
-
-static bool
-verify_stmt (gimple_stmt_iterator *gsi)
-{
-  tree addr;
-  struct walk_stmt_info wi;
-  bool last_in_block = gsi_one_before_end_p (*gsi);
-  gimple stmt = gsi_stmt (*gsi);
-  int lp_nr;
-
-  if (is_gimple_omp (stmt))
-    {
-      /* OpenMP directives are validated by the FE and never operated
-        on by the optimizers.  Furthermore, GIMPLE_OMP_FOR may contain
-        non-gimple expressions when the main index variable has had
-        its address taken.  This does not affect the loop itself
-        because the header of an GIMPLE_OMP_FOR is merely used to determine
-        how to setup the parallel iteration.  */
-      return false;
-    }
-
-  /* FIXME.  The C frontend passes unpromoted arguments in case it
-     didn't see a function declaration before the call.  */
-  if (is_gimple_call (stmt))
-    {
-      tree decl;
-
-      if (!is_gimple_call_addr (gimple_call_fn (stmt)))
-       {
-         error ("invalid function in call statement");
-         return true;
-       }
-
-      decl = gimple_call_fndecl (stmt);
-      if (decl
-         && TREE_CODE (decl) == FUNCTION_DECL
-         && DECL_LOOPING_CONST_OR_PURE_P (decl)
-         && (!DECL_PURE_P (decl))
-         && (!TREE_READONLY (decl)))
-       {
-         error ("invalid pure const state for function");
-         return true;
-       }
-    }
-
-  if (is_gimple_debug (stmt))
-    return false;
-
-  memset (&wi, 0, sizeof (wi));
-  addr = walk_gimple_op (gsi_stmt (*gsi), verify_expr, &wi);
-  if (addr)
-    {
-      debug_generic_expr (addr);
-      inform (gimple_location (gsi_stmt (*gsi)), "in statement");
-      debug_gimple_stmt (stmt);
-      return true;
-    }
-
-  /* If the statement is marked as part of an EH region, then it is
-     expected that the statement could throw.  Verify that when we
-     have optimizations that simplify statements such that we prove
-     that they cannot throw, that we update other data structures
-     to match.  */
-  lp_nr = lookup_stmt_eh_lp (stmt);
-  if (lp_nr != 0)
-    {
-      if (!stmt_could_throw_p (stmt))
-       {
-         /* During IPA passes, ipa-pure-const sets nothrow flags on calls
-            and they are updated on statements only after fixup_cfg
-            is executed at beggining of expansion stage.  */
-         if (cgraph_state != CGRAPH_STATE_IPA_SSA)
-           {
-             error ("statement marked for throw, but doesn%'t");
-             goto fail;
-           }
-       }
-      else if (lp_nr > 0 && !last_in_block && stmt_can_throw_internal (stmt))
-       {
-         error ("statement marked for throw in middle of block");
-         goto fail;
-       }
-    }
-
-  return false;
-
- fail:
-  debug_gimple_stmt (stmt);
-  return true;
-}
-
-
 /* Return true when the T can be shared.  */
 
 bool
@@ -4552,7 +4205,6 @@ tree_node_can_be_shared (tree t)
   return false;
 }
 
-
 /* Called via walk_gimple_stmt.  Verify tree sharing.  */
 
 static tree
@@ -4573,7 +4225,6 @@ verify_node_sharing (tree *tp, int *walk_subtrees, void *data)
   return NULL;
 }
 
-
 static bool eh_error_found;
 static int
 verify_eh_throw_stmt_node (void **slot, void *data)
@@ -4583,154 +4234,131 @@ verify_eh_throw_stmt_node (void **slot, void *data)
 
   if (!pointer_set_contains (visited, node->stmt))
     {
-      error ("Dead STMT in EH table");
+      error ("dead STMT in EH table");
       debug_gimple_stmt (node->stmt);
       eh_error_found = true;
     }
   return 1;
 }
 
+/* Verify the GIMPLE statements in the CFG of FN.  */
 
-/* Verify the GIMPLE statements in every basic block.  */
-
-void
-verify_stmts (void)
+DEBUG_FUNCTION void
+verify_gimple_in_cfg (struct function *fn)
 {
   basic_block bb;
-  gimple_stmt_iterator gsi;
   bool err = false;
   struct pointer_set_t *visited, *visited_stmts;
-  tree addr;
-  struct walk_stmt_info wi;
 
   timevar_push (TV_TREE_STMT_VERIFY);
   visited = pointer_set_create ();
   visited_stmts = pointer_set_create ();
 
-  memset (&wi, 0, sizeof (wi));
-  wi.info = (void *) visited;
-
-  FOR_EACH_BB (bb)
+  FOR_EACH_BB_FN (bb, fn)
     {
-      gimple phi;
-      size_t i;
+      gimple_stmt_iterator gsi;
 
       for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
        {
-         phi = gsi_stmt (gsi);
+         gimple phi = gsi_stmt (gsi);
+         bool err2 = false;
+         unsigned i;
+
          pointer_set_insert (visited_stmts, phi);
+
          if (gimple_bb (phi) != bb)
            {
              error ("gimple_bb (phi) is set to a wrong basic block");
-             err |= true;
+             err= true;
            }
 
+         err2 |= verify_gimple_phi (phi);
+
          for (i = 0; i < gimple_phi_num_args (phi); i++)
            {
-             tree t = gimple_phi_arg_def (phi, i);
-             tree addr;
-
-             if (!t)
-               {
-                 error ("missing PHI def");
-                 debug_gimple_stmt (phi);
-                 err |= true;
-                 continue;
-               }
-             /* Addressable variables do have SSA_NAMEs but they
-                are not considered gimple values.  */
-             else if (TREE_CODE (t) != SSA_NAME
-                      && TREE_CODE (t) != FUNCTION_DECL
-                      && !is_gimple_min_invariant (t))
-               {
-                 error ("PHI argument is not a GIMPLE value");
-                 debug_gimple_stmt (phi);
-                 debug_generic_expr (t);
-                 err |= true;
-               }
-
-             addr = walk_tree (&t, verify_node_sharing, visited, NULL);
+             tree arg = gimple_phi_arg_def (phi, i);
+             tree addr = walk_tree (&arg, verify_node_sharing, visited, NULL);
              if (addr)
                {
                  error ("incorrect sharing of tree nodes");
-                 debug_gimple_stmt (phi);
                  debug_generic_expr (addr);
-                 err |= true;
+                 err2 |= true;
                }
            }
 
-#ifdef ENABLE_TYPES_CHECKING
-         if (verify_gimple_phi (phi))
-           {
-             debug_gimple_stmt (phi);
-             err |= true;
-           }
-#endif
+         if (err2)
+           debug_gimple_stmt (phi);
+         err |= err2;
        }
 
-      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
+      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
        {
          gimple stmt = gsi_stmt (gsi);
-
-         if (gimple_code (stmt) == GIMPLE_WITH_CLEANUP_EXPR
-             || gimple_code (stmt) == GIMPLE_BIND)
-           {
-             error ("invalid GIMPLE statement");
-             debug_gimple_stmt (stmt);
-             err |= true;
-           }
+         bool err2 = false;
+         struct walk_stmt_info wi;
+         tree addr;
+         int lp_nr;
 
          pointer_set_insert (visited_stmts, stmt);
 
          if (gimple_bb (stmt) != bb)
            {
              error ("gimple_bb (stmt) is set to a wrong basic block");
-             debug_gimple_stmt (stmt);
-             err |= true;
+             err2 = true;
            }
 
-         if (gimple_code (stmt) == GIMPLE_LABEL)
+         err2 |= verify_gimple_stmt (stmt);
+
+         memset (&wi, 0, sizeof (wi));
+         wi.info = (void *) visited;
+         addr = walk_gimple_op (stmt, verify_node_sharing, &wi);
+         if (addr)
            {
-             tree decl = gimple_label_label (stmt);
-             int uid = LABEL_DECL_UID (decl);
+             error ("incorrect sharing of tree nodes");
+             debug_generic_expr (addr);
+             err2 |= true;
+           }
 
-             if (uid == -1
-                 || VEC_index (basic_block, label_to_block_map, uid) != bb)
+         /* ???  Instead of not checking these stmts at all the walker
+            should know its context via wi.  */
+         if (!is_gimple_debug (stmt)
+             && !is_gimple_omp (stmt))
+           {
+             memset (&wi, 0, sizeof (wi));
+             addr = walk_gimple_op (stmt, verify_expr, &wi);
+             if (addr)
                {
-                 error ("incorrect entry in label_to_block_map");
-                 err |= true;
+                 debug_generic_expr (addr);
+                 inform (gimple_location (stmt), "in statement");
+                 err2 |= true;
                }
+           }
 
-             uid = EH_LANDING_PAD_NR (decl);
-             if (uid)
+         /* If the statement is marked as part of an EH region, then it is
+            expected that the statement could throw.  Verify that when we
+            have optimizations that simplify statements such that we prove
+            that they cannot throw, that we update other data structures
+            to match.  */
+         lp_nr = lookup_stmt_eh_lp (stmt);
+         if (lp_nr != 0)
+           {
+             if (!stmt_could_throw_p (stmt))
                {
-                 eh_landing_pad lp = get_eh_landing_pad_from_number (uid);
-                 if (decl != lp->post_landing_pad)
-                   {
-                     error ("incorrect setting of landing pad number");
-                     err |= true;
-                   }
+                 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))
+               {
+                 error ("statement marked for throw in middle of block");
+                 err2 |= true;
                }
            }
 
-         err |= verify_stmt (&gsi);
-
-#ifdef ENABLE_TYPES_CHECKING
-         if (verify_types_in_gimple_stmt (gsi_stmt (gsi)))
-           {
-             debug_gimple_stmt (stmt);
-             err |= true;
-           }
-#endif
-         addr = walk_gimple_op (gsi_stmt (gsi), verify_node_sharing, &wi);
-         if (addr)
-           {
-             error ("incorrect sharing of tree nodes");
-             debug_gimple_stmt (stmt);
-             debug_generic_expr (addr);
-             err |= true;
-           }
-         gsi_next (&gsi);
+         if (err2)
+           debug_gimple_stmt (stmt);
+         err |= err2;
        }
     }
 
@@ -4740,8 +4368,8 @@ verify_stmts (void)
                   verify_eh_throw_stmt_node,
                   visited_stmts);
 
-  if (err | eh_error_found)
-    internal_error ("verify_stmts failed");
+  if (err || eh_error_found)
+    internal_error ("verify_gimple failed");
 
   pointer_set_destroy (visited);
   pointer_set_destroy (visited_stmts);
@@ -4808,6 +4436,15 @@ gimple_verify_flow_info (void)
              err = 1;
            }
 
+         if (prev_stmt && EH_LANDING_PAD_NR (label) != 0)
+           {
+             error ("EH landing pad label ");
+             print_generic_expr (stderr, label, 0);
+             fprintf (stderr, " is not first in a sequence of labels in bb %d",
+                      bb->index);
+             err = 1;
+           }
+
          if (label_to_block (label) != bb)
            {
              error ("label ");
@@ -4892,7 +4529,7 @@ gimple_verify_flow_info (void)
          {
            edge true_edge;
            edge false_edge;
-  
+
            extract_true_false_edges_from_block (bb, &true_edge, &false_edge);
 
            if (!true_edge
@@ -4932,6 +4569,10 @@ gimple_verify_flow_info (void)
            }
          break;
 
+       case GIMPLE_CALL:
+         if (!gimple_call_builtin_p (stmt, BUILT_IN_RETURN))
+           break;
+         /* ... fallthru ... */
        case GIMPLE_RETURN:
          if (!single_succ_p (bb)
              || (single_succ_edge (bb)->flags
@@ -5070,13 +4711,13 @@ gimple_make_forwarder_block (edge fallthru)
   for (gsi = gsi_start_phis (dummy); !gsi_end_p (gsi); gsi_next (&gsi))
     {
       gimple phi, new_phi;
-      
+
       phi = gsi_stmt (gsi);
       var = gimple_phi_result (phi);
       new_phi = create_phi_node (var, bb);
       SSA_NAME_DEF_STMT (var) = new_phi;
       gimple_phi_set_result (phi, make_ssa_name (SSA_NAME_VAR (var), phi));
-      add_phi_arg (new_phi, gimple_phi_result (phi), fallthru, 
+      add_phi_arg (new_phi, gimple_phi_result (phi), fallthru,
                   UNKNOWN_LOCATION);
     }
 
@@ -5220,7 +4861,7 @@ gimple_redirect_edge_and_branch (edge e, basic_block dest)
              {
                last = cases;
                CASE_LABEL (cases) = label;
-               cases = TREE_CHAIN (cases);
+               cases = CASE_CHAIN (cases);
              }
 
            /* If there was already an edge in the CFG, then we need
@@ -5229,9 +4870,10 @@ gimple_redirect_edge_and_branch (edge e, basic_block dest)
              {
                tree cases2 = get_cases_for_edge (e2, stmt);
 
-               TREE_CHAIN (last) = TREE_CHAIN (cases2);
-               TREE_CHAIN (cases2) = first;
+               CASE_CHAIN (last) = CASE_CHAIN (cases2);
+               CASE_CHAIN (cases2) = first;
              }
+           bitmap_set_bit (touched_switch_bbs, gimple_bb (stmt)->index);
          }
        else
          {
@@ -5250,14 +4892,23 @@ gimple_redirect_edge_and_branch (edge e, basic_block dest)
     case GIMPLE_ASM:
       {
        int i, n = gimple_asm_nlabels (stmt);
-       tree label = gimple_block_label (dest);
+       tree label = NULL;
 
        for (i = 0; i < n; ++i)
          {
            tree cons = gimple_asm_label_op (stmt, i);
            if (label_to_block (TREE_VALUE (cons)) == e->dest)
-             TREE_VALUE (cons) = label;
+             {
+               if (!label)
+                 label = gimple_block_label (dest);
+               TREE_VALUE (cons) = label;
+             }
          }
+
+       /* If we didn't find any label matching the former edge in the
+          asm labels, we must be redirecting the fallthrough
+          edge.  */
+       gcc_assert (label || (e->flags & EDGE_FALLTHRU));
       }
       break;
 
@@ -5363,7 +5014,7 @@ gimple_split_block (basic_block bb, void *stmt)
     return new_bb;
 
   /* Split the statement list - avoid re-creating new containers as this
-     brings ugly quadratic memory consumption in the inliner.  
+     brings ugly quadratic memory consumption in the inliner.
      (We are still quadratic since we need to update stmt BB pointers,
      sadly.)  */
   list = gsi_split_seq_before (&gsi);
@@ -5427,6 +5078,7 @@ gimple_duplicate_bb (basic_block bb)
     {
       def_operand_p def_p;
       ssa_op_iter op_iter;
+      tree lhs;
 
       stmt = gsi_stmt (gsi);
       if (gimple_code (stmt) == GIMPLE_LABEL)
@@ -5440,6 +5092,24 @@ gimple_duplicate_bb (basic_block bb)
       maybe_duplicate_eh_stmt (copy, stmt);
       gimple_duplicate_stmt_histograms (cfun, copy, cfun, stmt);
 
+      /* When copying around a stmt writing into a local non-user
+        aggregate, make sure it won't share stack slot with other
+        vars.  */
+      lhs = gimple_get_lhs (stmt);
+      if (lhs && TREE_CODE (lhs) != SSA_NAME)
+       {
+         tree base = get_base_address (lhs);
+         if (base
+             && (TREE_CODE (base) == VAR_DECL
+                 || TREE_CODE (base) == RESULT_DECL)
+             && DECL_IGNORED_P (base)
+             && !TREE_STATIC (base)
+             && !DECL_EXTERNAL (base)
+             && (TREE_CODE (base) != VAR_DECL
+                 || !DECL_HAS_VALUE_EXPR_P (base)))
+           DECL_NONSHAREABLE (base) = 1;
+       }
+
       /* Create new names for all the definitions created by COPY and
         add replacement mappings for each new name.  */
       FOR_EACH_SSA_DEF_OPERAND (def_p, copy, op_iter, SSA_OP_ALL_DEFS)
@@ -5495,7 +5165,7 @@ add_phi_args_after_copy_edge (edge e_copy)
       phi = gsi_stmt (psi);
       phi_copy = gsi_stmt (psi_copy);
       def = PHI_ARG_DEF_FROM_EDGE (phi, e);
-      add_phi_arg (phi_copy, def, e_copy, 
+      add_phi_arg (phi_copy, def, e_copy,
                   gimple_phi_arg_location_from_edge (phi, e));
     }
 }
@@ -5694,8 +5364,8 @@ gimple_duplicate_sese_region (edge entry, edge exit,
    is moved to ENTRY.  Returns true if duplication succeeds, false
    otherwise.
 
-   For example, 
+   For example,
+
    some_code;
    if (cond)
      A;
@@ -5733,6 +5403,10 @@ gimple_duplicate_sese_tail (edge entry ATTRIBUTE_UNUSED, edge exit ATTRIBUTE_UNU
   gimple_stmt_iterator gsi;
   gimple cond_stmt;
   edge sorig, snew;
+  basic_block exit_bb;
+  gimple_stmt_iterator psi;
+  gimple phi;
+  tree def;
 
   gcc_assert (EDGE_COUNT (exit->src->succs) == 2);
   exits[0] = exit;
@@ -5741,24 +5415,9 @@ gimple_duplicate_sese_tail (edge entry ATTRIBUTE_UNUSED, edge exit ATTRIBUTE_UNU
   if (!can_copy_bbs_p (region, n_region))
     return false;
 
-  /* Some sanity checking.  Note that we do not check for all possible
-     missuses of the functions.  I.e. if you ask to copy something weird
-     (e.g., in the example, if there is a jump from inside to the middle
-     of some_code, or come_code defines some of the values used in cond)
-     it will work, but the resulting code will not be correct.  */
-  for (i = 0; i < n_region; i++)
-    {
-      /* We do not handle subloops, i.e. all the blocks must belong to the
-        same loop.  */
-      if (region[i]->loop_father != orig_loop)
-       return false;
-
-      if (region[i] == orig_loop->latch)
-       return false;
-    }
-
   initialize_original_copy_tables ();
   set_loop_copy (orig_loop, loop);
+  duplicate_subloops (orig_loop, loop);
 
   if (!region_copy)
     {
@@ -5824,8 +5483,7 @@ gimple_duplicate_sese_tail (edge entry ATTRIBUTE_UNUSED, edge exit ATTRIBUTE_UNU
   cond_stmt = last_stmt (exit->src);
   gcc_assert (gimple_code (cond_stmt) == GIMPLE_COND);
   cond_stmt = gimple_copy (cond_stmt);
-  gimple_cond_set_lhs (cond_stmt, unshare_expr (gimple_cond_lhs (cond_stmt)));
-  gimple_cond_set_rhs (cond_stmt, unshare_expr (gimple_cond_rhs (cond_stmt)));
+
   gsi_insert_after (&gsi, cond_stmt, GSI_NEW_STMT);
 
   sorig = single_succ_edge (switch_bb);
@@ -5840,16 +5498,35 @@ gimple_duplicate_sese_tail (edge entry ATTRIBUTE_UNUSED, edge exit ATTRIBUTE_UNU
 
   /* Get rid of now superfluous conditions and associated edges (and phi node
      arguments).  */
+  exit_bb = exit->dest;
+
   e = redirect_edge_and_branch (exits[0], exits[1]->dest);
   PENDING_STMT (e) = NULL;
-  e = redirect_edge_and_branch (nexits[1], nexits[0]->dest);
-  PENDING_STMT (e) = NULL;
 
+  /* The latch of ORIG_LOOP was copied, and so was the backedge 
+     to the original header.  We redirect this backedge to EXIT_BB.  */
+  for (i = 0; i < n_region; i++)
+    if (get_bb_original (region_copy[i]) == orig_loop->latch)
+      {
+       gcc_assert (single_succ_edge (region_copy[i]));
+       e = redirect_edge_and_branch (single_succ_edge (region_copy[i]), exit_bb);
+       PENDING_STMT (e) = NULL;
+       for (psi = gsi_start_phis (exit_bb);
+            !gsi_end_p (psi);
+            gsi_next (&psi))
+         {
+           phi = gsi_stmt (psi);
+           def = PHI_ARG_DEF (phi, nexits[0]->dest_idx);
+           add_phi_arg (phi, def, e, gimple_phi_arg_location_from_edge (phi, e));
+         }
+      }
+  e = redirect_edge_and_branch (nexits[0], nexits[1]->dest);
+  PENDING_STMT (e) = NULL;
+  
   /* Anything that is outside of the region, but was dominated by something
      inside needs to update dominance info.  */
   iterate_fix_dominators (CDI_DOMINATORS, doms, false);
   VEC_free (basic_block, heap, doms);
-
   /* Update the SSA web.  */
   update_ssa (TODO_update_ssa);
 
@@ -5903,7 +5580,7 @@ replace_by_duplicate_decl (tree *tp, struct pointer_map_t *vars_map,
       if (SSA_VAR_P (t))
        {
          new_t = copy_var_decl (t, DECL_NAME (t), TREE_TYPE (t));
-         f->local_decls = tree_cons (NULL_TREE, new_t, f->local_decls);
+         add_local_decl (f, new_t);
        }
       else
        {
@@ -6014,7 +5691,7 @@ move_stmt_op (tree *tp, int *walk_subtrees, void *data)
               && !is_global_var (t))
              || TREE_CODE (t) == CONST_DECL)
            replace_by_duplicate_decl (tp, p->vars_map, p->to_context);
-         
+
          if (SSA_VAR_P (t)
              && gimple_in_ssa_p (cfun))
            {
@@ -6057,7 +5734,7 @@ move_stmt_eh_region_tree_nr (tree old_t_nr, struct move_stmt_d *p)
   old_nr = tree_low_cst (old_t_nr, 0);
   new_nr = move_stmt_eh_region_nr (old_nr, p);
 
-  return build_int_cst (NULL, new_nr);
+  return build_int_cst (integer_type_node, new_nr);
 }
 
 /* Like move_stmt_op, but for gimple statements.
@@ -6157,21 +5834,6 @@ move_stmt_r (gimple_stmt_iterator *gsi_p, bool *handled_ops_p,
   return NULL_TREE;
 }
 
-/* Marks virtual operands of all statements in basic blocks BBS for
-   renaming.  */
-
-void
-mark_virtual_ops_in_bb (basic_block bb)
-{
-  gimple_stmt_iterator gsi;
-
-  for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
-    mark_virtual_ops_for_renaming (gsi_stmt (gsi));
-
-  for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
-    mark_virtual_ops_for_renaming (gsi_stmt (gsi));
-}
-
 /* Move basic block BB from function CFUN to function DEST_FN.  The
    block is moved out of the original linked list and placed after
    block AFTER in the new list.  Also, the block is removed from the
@@ -6389,7 +6051,7 @@ replace_block_vars_by_duplicates (tree block, struct pointer_map_t *vars_map,
 {
   tree *tp, t;
 
-  for (tp = &BLOCK_VARS (block); *tp; tp = &TREE_CHAIN (*tp))
+  for (tp = &BLOCK_VARS (block); *tp; tp = &DECL_CHAIN (*tp))
     {
       t = *tp;
       if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != CONST_DECL)
@@ -6402,7 +6064,7 @@ replace_block_vars_by_duplicates (tree block, struct pointer_map_t *vars_map,
              SET_DECL_VALUE_EXPR (t, DECL_VALUE_EXPR (*tp));
              DECL_HAS_VALUE_EXPR_P (t) = 1;
            }
-         TREE_CHAIN (t) = TREE_CHAIN (*tp);
+         DECL_CHAIN (t) = DECL_CHAIN (*tp);
          *tp = t;
        }
     }
@@ -6519,7 +6181,7 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
     {
       eh_region region = NULL;
 
-      for (i = 0; VEC_iterate (basic_block, bbs, i, bb); i++)
+      FOR_EACH_VEC_ELT (basic_block, bbs, i, bb)
        region = find_outermost_region_in_block (saved_cfun, bb, region);
 
       init_eh_for_function ();
@@ -6548,7 +6210,7 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
   d.eh_map = eh_map;
   d.remap_decls_p = true;
 
-  for (i = 0; VEC_iterate (basic_block, bbs, i, bb); i++)
+  FOR_EACH_VEC_ELT (basic_block, bbs, i, bb)
     {
       /* No need to update edge counts on the last block.  It has
         already been updated earlier when we detached the region from
@@ -6613,7 +6275,7 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
     }
 
   set_immediate_dominator (CDI_DOMINATORS, bb, dom_entry);
-  for (i = 0; VEC_iterate (basic_block, dom_bbs, i, abb); i++)
+  FOR_EACH_VEC_ELT (basic_block, dom_bbs, i, abb)
     set_immediate_dominator (CDI_DOMINATORS, abb, bb);
   VEC_free (basic_block, heap, dom_bbs);
 
@@ -6638,7 +6300,7 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
 void
 dump_function_to_file (tree fn, FILE *file, int flags)
 {
-  tree arg, vars, var;
+  tree arg, var;
   struct function *dsf;
   bool ignore_topmost_bind = false, any_var = false;
   basic_block bb;
@@ -6654,9 +6316,9 @@ dump_function_to_file (tree fn, FILE *file, int flags)
       print_generic_expr (file, arg, dump_flags);
       if (flags & TDF_VERBOSE)
        print_node (file, "", arg, 4);
-      if (TREE_CHAIN (arg))
+      if (DECL_CHAIN (arg))
        fprintf (file, ", ");
-      arg = TREE_CHAIN (arg);
+      arg = DECL_CHAIN (arg);
     }
   fprintf (file, ")\n");
 
@@ -6678,15 +6340,14 @@ dump_function_to_file (tree fn, FILE *file, int flags)
 
   /* When GIMPLE is lowered, the variables are no longer available in
      BIND_EXPRs, so display them separately.  */
-  if (cfun && cfun->decl == fn && cfun->local_decls)
+  if (cfun && cfun->decl == fn && !VEC_empty (tree, cfun->local_decls))
     {
+      unsigned ix;
       ignore_topmost_bind = true;
 
       fprintf (file, "{\n");
-      for (vars = cfun->local_decls; vars; vars = TREE_CHAIN (vars))
+      FOR_EACH_LOCAL_DECL (cfun, ix, var)
        {
-         var = TREE_VALUE (vars);
-
          print_generic_decl (file, var, flags);
          if (flags & TDF_VERBOSE)
            print_node (file, "", var, 4);
@@ -6767,6 +6428,8 @@ dump_function_to_file (tree fn, FILE *file, int flags)
        fprintf (file, "}\n");
     }
 
+  if (flags & TDF_ENUMERATE_LOCALS)
+    dump_enumerated_decls (file, flags);
   fprintf (file, "\n\n");
 
   /* Restore CFUN.  */
@@ -6776,7 +6439,7 @@ dump_function_to_file (tree fn, FILE *file, int flags)
 
 /* Dump FUNCTION_DECL FN to stderr using FLAGS (see TDF_* in tree.h)  */
 
-void
+DEBUG_FUNCTION void
 debug_function (tree fn, int flags)
 {
   dump_function_to_file (fn, stderr, flags);
@@ -6810,7 +6473,7 @@ print_succ_bbs (FILE *file, basic_block bb)
 
 /* Print to FILE the basic block BB following the VERBOSITY level.  */
 
-void 
+void
 print_loops_bb (FILE *file, basic_block bb, int indent, int verbosity)
 {
   char *s_indent = (char *) alloca ((size_t) indent + 1);
@@ -6856,7 +6519,7 @@ print_loop (FILE *file, struct loop *loop, int indent, int verbosity)
   s_indent[indent] = '\0';
 
   /* Print loop's header.  */
-  fprintf (file, "%sloop_%d (header = %d, latch = %d", s_indent, 
+  fprintf (file, "%sloop_%d (header = %d, latch = %d", s_indent,
           loop->num, loop->header->index, loop->latch->index);
   fprintf (file, ", niter = ");
   print_generic_expr (file, loop->nb_iterations, 0);
@@ -6917,7 +6580,7 @@ print_loops (FILE *file, int verbosity)
 
 /* Debugging loops structure at tree level, at some VERBOSITY level.  */
 
-void
+DEBUG_FUNCTION void
 debug_loops (int verbosity)
 {
   print_loops (stderr, verbosity);
@@ -6925,7 +6588,7 @@ debug_loops (int verbosity)
 
 /* Print on stderr the code of LOOP, at some VERBOSITY level.  */
 
-void
+DEBUG_FUNCTION void
 debug_loop (struct loop *loop, int verbosity)
 {
   print_loop (stderr, loop, 0, verbosity);
@@ -6934,7 +6597,7 @@ debug_loop (struct loop *loop, int verbosity)
 /* Print on stderr the code of loop number NUM, at some VERBOSITY
    level.  */
 
-void
+DEBUG_FUNCTION void
 debug_loop_num (unsigned num, int verbosity)
 {
   debug_loop (get_loop (num), verbosity);
@@ -6948,7 +6611,7 @@ static bool
 gimple_block_ends_with_call_p (basic_block bb)
 {
   gimple_stmt_iterator gsi = gsi_last_nondebug_bb (bb);
-  return is_gimple_call (gsi_stmt (gsi));
+  return !gsi_end_p (gsi) && is_gimple_call (gsi_stmt (gsi));
 }
 
 
@@ -7049,7 +6712,7 @@ gimple_flow_call_edges_add (sbitmap blocks)
   if (check_last_block)
     {
       basic_block bb = EXIT_BLOCK_PTR->prev_bb;
-      gimple_stmt_iterator gsi = gsi_last_bb (bb);
+      gimple_stmt_iterator gsi = gsi_last_nondebug_bb (bb);
       gimple t = NULL;
 
       if (!gsi_end_p (gsi))
@@ -7083,7 +6746,7 @@ gimple_flow_call_edges_add (sbitmap blocks)
       if (blocks && !TEST_BIT (blocks, i))
        continue;
 
-      gsi = gsi_last_bb (bb);
+      gsi = gsi_last_nondebug_bb (bb);
       if (!gsi_end_p (gsi))
        {
          last_stmt = gsi_stmt (gsi);
@@ -7129,39 +6792,6 @@ gimple_flow_call_edges_add (sbitmap blocks)
   return blocks_split;
 }
 
-/* Purge dead abnormal call edges from basic block BB.  */
-
-bool
-gimple_purge_dead_abnormal_call_edges (basic_block bb)
-{
-  bool changed = gimple_purge_dead_eh_edges (bb);
-
-  if (cfun->has_nonlocal_label)
-    {
-      gimple stmt = last_stmt (bb);
-      edge_iterator ei;
-      edge e;
-
-      if (!(stmt && stmt_can_make_abnormal_goto (stmt)))
-       for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); )
-         {
-           if (e->flags & EDGE_ABNORMAL)
-             {
-               remove_edge (e);
-               changed = true;
-             }
-           else
-             ei_next (&ei);
-         }
-
-      /* See gimple_purge_dead_eh_edges below.  */
-      if (changed)
-       free_dominance_info (CDI_DOMINATORS);
-    }
-
-  return changed;
-}
-
 /* Removes edge E and all the blocks dominated by it, and updates dominance
    information.  The IL in E->src needs to be updated separately.
    If dominance info is not available, only the edge E is removed.*/
@@ -7222,7 +6852,7 @@ remove_edge_and_dominated_blocks (edge e)
   else
     {
       bbs_to_remove = get_all_dominated_blocks (CDI_DOMINATORS, e->dest);
-      for (i = 0; VEC_iterate (basic_block, bbs_to_remove, i, bb); i++)
+      FOR_EACH_VEC_ELT (basic_block, bbs_to_remove, i, bb)
        {
          FOR_EACH_EDGE (f, ei, bb->succs)
            {
@@ -7230,7 +6860,7 @@ remove_edge_and_dominated_blocks (edge e)
                bitmap_set_bit (df, f->dest->index);
            }
        }
-      for (i = 0; VEC_iterate (basic_block, bbs_to_remove, i, bb); i++)
+      FOR_EACH_VEC_ELT (basic_block, bbs_to_remove, i, bb)
        bitmap_clear_bit (df, bb->index);
 
       EXECUTE_IF_SET_IN_BITMAP (df, 0, i, bi)
@@ -7263,14 +6893,14 @@ remove_edge_and_dominated_blocks (edge e)
 
   /* Update the dominance information.  The immediate dominator may change only
      for blocks whose immediate dominator belongs to DF_IDOM:
-   
+
      Suppose that idom(X) = Y before removal of E and idom(X) != Y after the
      removal.  Let Z the arbitrary block such that idom(Z) = Y and
      Z dominates X after the removal.  Before removal, there exists a path P
      from Y to X that avoids Z.  Let F be the last edge on P that is
      removed, and let W = F->dest.  Before removal, idom(W) = Y (since Y
      dominates W, and because of P, Z does not dominate W), and W belongs to
-     the dominance frontier of E.  Therefore, Y belongs to DF_IDOM.  */ 
+     the dominance frontier of E.  Therefore, Y belongs to DF_IDOM.  */
   EXECUTE_IF_SET_IN_BITMAP (df_idom, 0, i, bi)
     {
       bb = BASIC_BLOCK (i);
@@ -7315,6 +6945,8 @@ gimple_purge_dead_eh_edges (basic_block bb)
   return changed;
 }
 
+/* Purge dead EH edges from basic block listed in BLOCKS.  */
+
 bool
 gimple_purge_all_dead_eh_edges (const_bitmap blocks)
 {
@@ -7336,6 +6968,59 @@ gimple_purge_all_dead_eh_edges (const_bitmap blocks)
   return changed;
 }
 
+/* Purge dead abnormal call edges from basic block BB.  */
+
+bool
+gimple_purge_dead_abnormal_call_edges (basic_block bb)
+{
+  bool changed = false;
+  edge e;
+  edge_iterator ei;
+  gimple stmt = last_stmt (bb);
+
+  if (!cfun->has_nonlocal_label)
+    return false;
+
+  if (stmt && stmt_can_make_abnormal_goto (stmt))
+    return false;
+
+  for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); )
+    {
+      if (e->flags & EDGE_ABNORMAL)
+       {
+         remove_edge_and_dominated_blocks (e);
+         changed = true;
+       }
+      else
+       ei_next (&ei);
+    }
+
+  return changed;
+}
+
+/* Purge dead abnormal call edges from basic block listed in BLOCKS.  */
+
+bool
+gimple_purge_all_dead_abnormal_call_edges (const_bitmap blocks)
+{
+  bool changed = false;
+  unsigned i;
+  bitmap_iterator bi;
+
+  EXECUTE_IF_SET_IN_BITMAP (blocks, 0, i, bi)
+    {
+      basic_block bb = BASIC_BLOCK (i);
+
+      /* Earlier gimple_purge_dead_abnormal_call_edges could have removed
+        this basic block already.  */
+      gcc_assert (bb || changed);
+      if (bb != NULL)
+       changed |= gimple_purge_dead_abnormal_call_edges (bb);
+    }
+
+  return changed;
+}
+
 /* This function is called whenever a new edge is created or
    redirected.  */
 
@@ -7344,7 +7029,7 @@ gimple_execute_on_growing_pred (edge e)
 {
   basic_block bb = e->dest;
 
-  if (phi_nodes (bb))
+  if (!gimple_seq_empty_p (phi_nodes (bb)))
     reserve_phi_args_for_new_edge (bb);
 }
 
@@ -7354,7 +7039,7 @@ gimple_execute_on_growing_pred (edge e)
 static void
 gimple_execute_on_shrinking_pred (edge e)
 {
-  if (phi_nodes (e->dest))
+  if (!gimple_seq_empty_p (phi_nodes (e->dest)))
     remove_phi_args (e);
 }
 
@@ -7442,15 +7127,16 @@ struct cfg_hooks gimple_cfg_hooks = {
   gimple_can_merge_blocks_p,   /* can_merge_blocks_p  */
   gimple_merge_blocks,         /* merge_blocks  */
   gimple_predict_edge,         /* predict_edge  */
-  gimple_predicted_by_p,               /* predicted_by_p  */
+  gimple_predicted_by_p,       /* predicted_by_p  */
   gimple_can_duplicate_bb_p,   /* can_duplicate_block_p  */
   gimple_duplicate_bb,         /* duplicate_block  */
   gimple_split_edge,           /* split_edge  */
   gimple_make_forwarder_block, /* make_forward_block  */
   NULL,                                /* tidy_fallthru_edge  */
+  NULL,                                /* force_nonfallthru */
   gimple_block_ends_with_call_p,/* block_ends_with_call_p */
   gimple_block_ends_with_condjump_p, /* block_ends_with_condjump_p */
-  gimple_flow_call_edges_add,     /* flow_call_edges_add */
+  gimple_flow_call_edges_add,   /* flow_call_edges_add */
   gimple_execute_on_growing_pred,      /* execute_on_growing_pred */
   gimple_execute_on_shrinking_pred, /* execute_on_shrinking_pred */
   gimple_duplicate_loop_to_header_edge, /* duplicate loop for trees */
@@ -7480,11 +7166,11 @@ split_critical_edges (void)
         {
          if (EDGE_CRITICAL_P (e) && !(e->flags & EDGE_ABNORMAL))
            split_edge (e);
-         /* PRE inserts statements to edges and expects that 
+         /* PRE inserts statements to edges and expects that
             since split_critical_edges was done beforehand, committing edge
             insertions will not split more edges.  In addition to critical
             edges we must split edges that have multiple successors and
-            end by control flow statements, such as RESX. 
+            end by control flow statements, such as RESX.
             Go ahead and split them too.  This matches the logic in
             gimple_find_edge_insert_loc.  */
          else if ((!single_pred_p (e->dest)
@@ -7498,7 +7184,9 @@ split_critical_edges (void)
              gsi = gsi_last_bb (e->src);
              if (!gsi_end_p (gsi)
                  && stmt_ends_bb_p (gsi_stmt (gsi))
-                 && gimple_code (gsi_stmt (gsi)) != GIMPLE_RETURN)
+                 && (gimple_code (gsi_stmt (gsi)) != GIMPLE_RETURN
+                     && !gimple_call_builtin_p (gsi_stmt (gsi),
+                                                BUILT_IN_RETURN)))
                split_edge (e);
            }
        }
@@ -7522,7 +7210,7 @@ struct gimple_opt_pass pass_split_crit_edges =
   PROP_no_crit_edges,            /* properties_provided */
   0,                             /* properties_destroyed */
   0,                             /* todo_flags_start */
-  TODO_dump_func | TODO_verify_flow  /* todo_flags_finish */
+  TODO_verify_flow               /* todo_flags_finish */
  }
 };
 
@@ -7596,7 +7284,8 @@ execute_warn_function_return (void)
       FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds)
        {
          last = last_stmt (e->src);
-         if (gimple_code (last) == GIMPLE_RETURN
+         if ((gimple_code (last) == GIMPLE_RETURN
+              || gimple_call_builtin_p (last, BUILT_IN_RETURN))
              && (location = gimple_location (last)) != UNKNOWN_LOCATION)
            break;
        }
@@ -7660,7 +7349,7 @@ struct gimple_opt_pass pass_warn_function_return =
 {
  {
   GIMPLE_PASS,
-  NULL,                                        /* name */
+  "*warn_function_return",             /* name */
   NULL,                                        /* gate */
   execute_warn_function_return,                /* execute */
   NULL,                                        /* sub */
@@ -7680,22 +7369,24 @@ struct gimple_opt_pass pass_warn_function_return =
 static unsigned int
 execute_warn_function_noreturn (void)
 {
-  if (warn_missing_noreturn
-      && !TREE_THIS_VOLATILE (cfun->decl)
-      && EDGE_COUNT (EXIT_BLOCK_PTR->preds) == 0
-      && !lang_hooks.missing_noreturn_ok_p (cfun->decl))
-    warning_at (DECL_SOURCE_LOCATION (cfun->decl), OPT_Wmissing_noreturn,
-               "function might be possible candidate "
-               "for attribute %<noreturn%>");
+  if (!TREE_THIS_VOLATILE (current_function_decl)
+      && EDGE_COUNT (EXIT_BLOCK_PTR->preds) == 0)
+    warn_function_noreturn (current_function_decl);
   return 0;
 }
 
+static bool
+gate_warn_function_noreturn (void)
+{
+  return warn_suggest_attribute_noreturn;
+}
+
 struct gimple_opt_pass pass_warn_function_noreturn =
 {
  {
   GIMPLE_PASS,
-  NULL,                                        /* name */
-  NULL,                                        /* gate */
+  "*warn_function_noreturn",           /* name */
+  gate_warn_function_noreturn,         /* gate */
   execute_warn_function_noreturn,      /* execute */
   NULL,                                        /* sub */
   NULL,                                        /* next */
@@ -7743,12 +7434,14 @@ do_warn_unused_result (gimple_seq seq)
        case GIMPLE_CALL:
          if (gimple_call_lhs (g))
            break;
+         if (gimple_call_internal_p (g))
+           break;
 
          /* This is a naked call, as opposed to a GIMPLE_CALL with an
             LHS.  All calls whose value is ignored should be
             represented like this.  Look for the attribute.  */
          fdecl = gimple_call_fndecl (g);
-         ftype = TREE_TYPE (TREE_TYPE (gimple_call_fn (g)));
+         ftype = gimple_call_fntype (g);
 
          if (lookup_attribute ("warn_unused_result", TYPE_ATTRIBUTES (ftype)))
            {
@@ -7804,4 +7497,3 @@ struct gimple_opt_pass pass_warn_unused_result =
     0,                                 /* todo_flags_finish */
   }
 };
-