OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / tree-cfg.c
index 85d588a..a3fed03 100644 (file)
@@ -1,5 +1,6 @@
 /* Control flow functions for trees.
-   Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006
+   Free Software Foundation, Inc.
    Contributed by Diego Novillo <dnovillo@redhat.com>
 
 This file is part of GCC.
@@ -99,14 +100,12 @@ static void factor_computed_gotos (void);
 
 /* Edges.  */
 static void make_edges (void);
-static void make_ctrl_stmt_edges (basic_block);
-static void make_exit_edges (basic_block);
 static void make_cond_expr_edges (basic_block);
 static void make_switch_expr_edges (basic_block);
 static void make_goto_expr_edges (basic_block);
 static edge tree_redirect_edge_and_branch (edge, basic_block);
 static edge tree_try_redirect_by_replacing_jump (edge, basic_block);
-static void split_critical_edges (void);
+static unsigned int split_critical_edges (void);
 
 /* Various helpers.  */
 static inline bool stmt_starts_bb_p (tree, tree);
@@ -207,11 +206,11 @@ build_tree_cfg (tree *tp)
   /* Write the flowgraph to a VCG file.  */
   {
     int local_dump_flags;
-    FILE *dump_file = dump_begin (TDI_vcg, &local_dump_flags);
-    if (dump_file)
+    FILE *vcg_file = dump_begin (TDI_vcg, &local_dump_flags);
+    if (vcg_file)
       {
-       tree_cfg2vcg (dump_file);
-       dump_end (TDI_vcg, dump_file);
+       tree_cfg2vcg (vcg_file);
+       dump_end (TDI_vcg, vcg_file);
       }
   }
 
@@ -224,10 +223,11 @@ build_tree_cfg (tree *tp)
     dump_tree_cfg (dump_file, dump_flags);
 }
 
-static void
+static unsigned int
 execute_build_cfg (void)
 {
   build_tree_cfg (&DECL_SAVED_TREE (current_function_decl));
+  return 0;
 }
 
 struct tree_opt_pass pass_build_cfg =
@@ -247,9 +247,9 @@ struct tree_opt_pass pass_build_cfg =
   0                                    /* letter */
 };
 
-/* Search the CFG for any computed gotos.  If found, factor them to a 
+/* Search the CFG for any computed gotos.  If found, factor them to a
    common computed goto site.  Also record the location of that site so
-   that we can un-factor the gotos after we have converted back to 
+   that we can un-factor the gotos after we have converted back to
    normal form.  */
 
 static void
@@ -264,7 +264,7 @@ factor_computed_gotos (void)
   /* We know there are one or more computed gotos in this function.
      Examine the last statement in each basic block to see if the block
      ends with a computed goto.  */
-       
+
   FOR_EACH_BB (bb)
     {
       block_stmt_iterator bsi = bsi_last (bb);
@@ -446,6 +446,7 @@ static void
 make_edges (void)
 {
   basic_block bb;
+  struct omp_region *cur_region = NULL;
 
   /* Create an edge from entry to the first block with executable
      statements in it.  */
@@ -454,188 +455,143 @@ make_edges (void)
   /* Traverse the basic block array placing edges.  */
   FOR_EACH_BB (bb)
     {
-      tree first = first_stmt (bb);
       tree last = last_stmt (bb);
+      bool fallthru;
 
-      if (first)
+      if (last)
        {
-         /* Edges for statements that always alter flow control.  */
-         if (is_ctrl_stmt (last))
-           make_ctrl_stmt_edges (bb);
-
-         /* Edges for statements that sometimes alter flow control.  */
-         if (is_ctrl_altering_stmt (last))
-           make_exit_edges (bb);
-       }
-
-      /* Finally, if no edges were created above, this is a regular
-        basic block that only needs a fallthru edge.  */
-      if (EDGE_COUNT (bb->succs) == 0)
-       make_edge (bb, bb->next_bb, EDGE_FALLTHRU);
-    }
-
-  /* We do not care about fake edges, so remove any that the CFG
-     builder inserted for completeness.  */
-  remove_fake_exit_edges ();
-
-  /* Fold COND_EXPR_COND of each COND_EXPR.  */
-  fold_cond_expr_cond ();
-
-  /* Clean up the graph and warn for unreachable code.  */
-  cleanup_tree_cfg ();
-}
-
-
-/* Link an OMP_SECTIONS block to all the OMP_SECTION blocks in its body.  */
-
-static void
-make_omp_sections_edges (basic_block bb)
-{
-  basic_block exit_bb;
-  size_t i, n;
-  tree vec, stmt;
-
-  stmt = last_stmt (bb);
-  vec = OMP_SECTIONS_SECTIONS (stmt);
-  n = TREE_VEC_LENGTH (vec);
-  exit_bb = bb_for_stmt (TREE_VEC_ELT (vec, n - 1));
-
-  for (i = 0; i < n - 1; i += 2)
-    {
-      basic_block start_bb = bb_for_stmt (TREE_VEC_ELT (vec, i));
-      basic_block end_bb = bb_for_stmt (TREE_VEC_ELT (vec, i + 1));
-      make_edge (bb, start_bb, EDGE_ABNORMAL);
-      make_edge (end_bb, exit_bb, EDGE_FALLTHRU);
-    }
-
-  /* Once the CFG has been built, the vector of sections is no longer
-     useful.  The region can be easily obtained with build_omp_regions.
-     Furthermore, this sharing of tree expressions is not allowed by the
-     statement verifier.  */
-  OMP_SECTIONS_SECTIONS (stmt) = NULL_TREE;
-}
-
-
-
-/* Create edges for control statement at basic block BB.  */
-
-static void
-make_ctrl_stmt_edges (basic_block bb)
-{
-  tree last = last_stmt (bb);
+         enum tree_code code = TREE_CODE (last);
+         switch (code)
+           {
+           case GOTO_EXPR:
+             make_goto_expr_edges (bb);
+             fallthru = false;
+             break;
+           case RETURN_EXPR:
+             make_edge (bb, EXIT_BLOCK_PTR, 0);
+             fallthru = false;
+             break;
+           case COND_EXPR:
+             make_cond_expr_edges (bb);
+             fallthru = false;
+             break;
+           case SWITCH_EXPR:
+             make_switch_expr_edges (bb);
+             fallthru = false;
+             break;
+           case RESX_EXPR:
+             make_eh_edges (last);
+             fallthru = false;
+             break;
 
-  gcc_assert (last);
-  switch (TREE_CODE (last))
-    {
-    case GOTO_EXPR:
-      make_goto_expr_edges (bb);
-      break;
+           case CALL_EXPR:
+             /* If this function receives a nonlocal goto, then we need to
+                make edges from this call site to all the nonlocal goto
+                handlers.  */
+             if (TREE_SIDE_EFFECTS (last)
+                 && current_function_has_nonlocal_label)
+               make_goto_expr_edges (bb);
 
-    case RETURN_EXPR:
-      make_edge (bb, EXIT_BLOCK_PTR, 0);
-      break;
+             /* If this statement has reachable exception handlers, then
+                create abnormal edges to them.  */
+             make_eh_edges (last);
 
-    case COND_EXPR:
-      make_cond_expr_edges (bb);
-      break;
+             /* Some calls are known not to return.  */
+             fallthru = !(call_expr_flags (last) & ECF_NORETURN);
+             break;
 
-    case SWITCH_EXPR:
-      make_switch_expr_edges (bb);
-      break;
+           case MODIFY_EXPR:
+             if (is_ctrl_altering_stmt (last))
+               {
+                 /* A MODIFY_EXPR may have a CALL_EXPR on its RHS and the
+                    CALL_EXPR may have an abnormal edge.  Search the RHS for
+                    this case and create any required edges.  */
+                 tree op = get_call_expr_in (last);
+                 if (op && TREE_SIDE_EFFECTS (op)
+                     && current_function_has_nonlocal_label)
+                   make_goto_expr_edges (bb);
+
+                 make_eh_edges (last);
+               }
+             fallthru = true;
+             break;
 
-    case RESX_EXPR:
-      make_eh_edges (last);
-      /* Yet another NORETURN hack.  */
-      if (EDGE_COUNT (bb->succs) == 0)
-       make_edge (bb, EXIT_BLOCK_PTR, EDGE_FAKE);
-      break;
+           case OMP_PARALLEL:
+           case OMP_FOR:
+           case OMP_SINGLE:
+           case OMP_MASTER:
+           case OMP_ORDERED:
+           case OMP_CRITICAL:
+           case OMP_SECTION:
+             cur_region = new_omp_region (bb, code, cur_region);
+             fallthru = true;
+             break;
 
-    default:
-      gcc_unreachable ();
-    }
-}
+           case OMP_SECTIONS:
+             cur_region = new_omp_region (bb, code, cur_region);
+             fallthru = false;
+             break;
 
+           case OMP_RETURN:
+             /* In the case of an OMP_SECTION, the edge will go somewhere
+                other than the next block.  This will be created later.  */
+             cur_region->exit = bb;
+             fallthru = cur_region->type != OMP_SECTION;
+             cur_region = cur_region->outer;
+             break;
 
-/* Create exit edges for statements in block BB that alter the flow of
-   control.  Statements that alter the control flow are 'goto', 'return'
-   and calls to non-returning functions.  */
+           case OMP_CONTINUE:
+             cur_region->cont = bb;
+             switch (cur_region->type)
+               {
+               case OMP_FOR:
+                 /* ??? Technically there should be a some sort of loopback
+                    edge here, but it goes to a block that doesn't exist yet,
+                    and without it, updating the ssa form would be a real
+                    bear.  Fortunately, we don't yet do ssa before expanding
+                    these nodes.  */
+                 break;
+
+               case OMP_SECTIONS:
+                 /* Wire up the edges into and out of the nested sections.  */
+                 /* ??? Similarly wrt loopback.  */
+                 {
+                   struct omp_region *i;
+                   for (i = cur_region->inner; i ; i = i->next)
+                     {
+                       gcc_assert (i->type == OMP_SECTION);
+                       make_edge (cur_region->entry, i->entry, 0);
+                       make_edge (i->exit, bb, EDGE_FALLTHRU);
+                     }
+                 }
+                 break;
 
-static void
-make_exit_edges (basic_block bb)
-{
-  tree last = last_stmt (bb), op;
+               default:
+                 gcc_unreachable ();
+               }
+             fallthru = true;
+             break;
 
-  gcc_assert (last);
-  switch (TREE_CODE (last))
-    {
-    case RESX_EXPR:
-      break;
-    case CALL_EXPR:
-      /* If this function receives a nonlocal goto, then we need to
-        make edges from this call site to all the nonlocal goto
-        handlers.  */
-      if (TREE_SIDE_EFFECTS (last)
-         && current_function_has_nonlocal_label)
-       make_goto_expr_edges (bb);
-
-      /* If this statement has reachable exception handlers, then
-        create abnormal edges to them.  */
-      make_eh_edges (last);
-
-      /* Some calls are known not to return.  For such calls we create
-        a fake edge.
-
-        We really need to revamp how we build edges so that it's not
-        such a bloody pain to avoid creating edges for this case since
-        all we do is remove these edges when we're done building the
-        CFG.  */
-      if (call_expr_flags (last) & ECF_NORETURN)
-       {
-         make_edge (bb, EXIT_BLOCK_PTR, EDGE_FAKE);
-         return;
+           default:
+             gcc_assert (!stmt_ends_bb_p (last));
+             fallthru = true;
+           }
        }
+      else
+       fallthru = true;
 
-      /* Don't forget the fall-thru edge.  */
-      make_edge (bb, bb->next_bb, EDGE_FALLTHRU);
-      break;
-
-    case MODIFY_EXPR:
-      /* A MODIFY_EXPR may have a CALL_EXPR on its RHS and the CALL_EXPR
-        may have an abnormal edge.  Search the RHS for this case and
-        create any required edges.  */
-      op = get_call_expr_in (last);
-      if (op && TREE_SIDE_EFFECTS (op)
-         && current_function_has_nonlocal_label)
-       make_goto_expr_edges (bb);
-
-      make_eh_edges (last);
-      make_edge (bb, bb->next_bb, EDGE_FALLTHRU);
-      break;
-
-    case OMP_PARALLEL:
-    case OMP_FOR:
-    case OMP_SINGLE:
-    case OMP_MASTER:
-    case OMP_ORDERED:
-    case OMP_CRITICAL:
-      make_edge (bb, bb->next_bb, EDGE_ABNORMAL);
-
-    case OMP_RETURN_EXPR:
-      if (EDGE_COUNT (bb->succs) == 0)
+      if (fallthru)
        make_edge (bb, bb->next_bb, EDGE_FALLTHRU);
-      break;
+    }
 
-    case OMP_SECTIONS:
-      make_omp_sections_edges (bb);
-      break;
+  if (root_omp_region)
+    free_omp_regions ();
 
-    case OMP_SECTION:
-      make_edge (bb, bb->next_bb, EDGE_FALLTHRU);
-      break;
+  /* Fold COND_EXPR_COND of each COND_EXPR.  */
+  fold_cond_expr_cond ();
 
-    default:
-      gcc_unreachable ();
-    }
+  /* Clean up the graph and warn for unreachable code.  */
+  cleanup_tree_cfg ();
 }
 
 
@@ -702,7 +658,7 @@ edge_to_cases_eq (const void *p1, const void *p2)
 /* Called for each element in the hash table (P) as we delete the
    edge to cases hash table.
 
-   Clear all the TREE_CHAINs to prevent problems with copying of 
+   Clear all the TREE_CHAINs to prevent problems with copying of
    SWITCH_EXPRs and structure sharing rules, then free the hash table
    element.  */
 
@@ -803,7 +759,7 @@ get_cases_for_edge (edge e, tree t)
      chains available.  Return NULL so the caller can detect this case.  */
   if (!recording_case_labels_p ())
     return NULL;
-  
+
 restart:
   elt.e = e;
   elt.case_labels = NULL;
@@ -865,7 +821,7 @@ label_to_block_fn (struct function *ifun, tree dest)
      and undefined variable warnings quite right.  */
   if ((errorcount || sorrycount) && uid < 0)
     {
-      block_stmt_iterator bsi = 
+      block_stmt_iterator bsi =
        bsi_start (BASIC_BLOCK (NUM_FIXED_BLOCKS));
       tree stmt;
 
@@ -886,7 +842,7 @@ make_goto_expr_edges (basic_block bb)
 {
   tree goto_t;
   basic_block target_bb;
-  int for_call;
+  bool for_call;
   block_stmt_iterator last = bsi_last (bb);
 
   goto_t = bsi_stmt (last);
@@ -895,11 +851,11 @@ make_goto_expr_edges (basic_block bb)
      CALL_EXPR or MODIFY_EXPR), then the edge is an abnormal edge resulting
      from a nonlocal goto.  */
   if (TREE_CODE (goto_t) != GOTO_EXPR)
-    for_call = 1;
+    for_call = true;
   else
     {
       tree dest = GOTO_DESTINATION (goto_t);
-      for_call = 0;
+      for_call = false;
 
       /* A GOTO to a local label creates normal edges.  */
       if (simple_goto_p (goto_t))
@@ -938,21 +894,17 @@ make_goto_expr_edges (basic_block bb)
          if (
              /* Computed GOTOs.  Make an edge to every label block that has
                 been marked as a potential target for a computed goto.  */
-             (FORCED_LABEL (LABEL_EXPR_LABEL (target)) && for_call == 0)
+             (FORCED_LABEL (LABEL_EXPR_LABEL (target)) && !for_call)
              /* Nonlocal GOTO target.  Make an edge to every label block
                 that has been marked as a potential target for a nonlocal
                 goto.  */
-             || (DECL_NONLOCAL (LABEL_EXPR_LABEL (target)) && for_call == 1))
+             || (DECL_NONLOCAL (LABEL_EXPR_LABEL (target)) && for_call))
            {
              make_edge (bb, target_bb, EDGE_ABNORMAL);
              break;
            }
        }
     }
-
-  /* Degenerate case of computed goto with no labels.  */
-  if (!for_call && EDGE_COUNT (bb->succs) == 0)
-    make_edge (bb, EXIT_BLOCK_PTR, EDGE_FAKE);
 }
 
 
@@ -1073,13 +1025,13 @@ cleanup_dead_labels (void)
 
            break;
          }
-  
+
        case SWITCH_EXPR:
          {
            size_t i;
            tree vec = SWITCH_LABELS (stmt);
            size_t n = TREE_VEC_LENGTH (vec);
-  
+
            /* Replace all destination labels.  */
            for (i = 0; i < n; ++i)
              {
@@ -1159,7 +1111,7 @@ group_case_labels (void)
          int old_size = TREE_VEC_LENGTH (labels);
          int i, j, new_size = old_size;
          tree default_case = TREE_VEC_ELT (labels, old_size - 1);
-         tree default_label;
+         tree default_label;
 
          /* The default label is always the last case in a switch
             statement after gimplification.  */
@@ -1253,7 +1205,7 @@ tree_can_merge_blocks_p (basic_block a, basic_block b)
 
   if (b == EXIT_BLOCK_PTR)
     return false;
-  
+
   /* If A ends by a statement causing exceptions or something similar, we
      cannot merge the blocks.  */
   stmt = last_stmt (a);
@@ -1307,54 +1259,42 @@ replace_uses_by (tree name, tree val)
   tree stmt;
   edge e;
   unsigned i;
-  VEC(tree,heap) *stmts = VEC_alloc (tree, heap, 20);
 
-  FOR_EACH_IMM_USE_SAFE (use, imm_iter, name)
+
+  FOR_EACH_IMM_USE_STMT (stmt, imm_iter, name)
     {
-      stmt = USE_STMT (use);
-      replace_exp (use, val);
+      FOR_EACH_IMM_USE_ON_STMT (use, imm_iter)
+        {
+         replace_exp (use, val);
 
-      if (TREE_CODE (stmt) == PHI_NODE)
-       {
-         e = PHI_ARG_EDGE (stmt, PHI_ARG_INDEX_FROM_USE (use));
-         if (e->flags & EDGE_ABNORMAL)
+         if (TREE_CODE (stmt) == PHI_NODE)
            {
-             /* This can only occur for virtual operands, since
-                for the real ones SSA_NAME_OCCURS_IN_ABNORMAL_PHI (name))
-                would prevent replacement.  */
-             gcc_assert (!is_gimple_reg (name));
-             SSA_NAME_OCCURS_IN_ABNORMAL_PHI (val) = 1;
+             e = PHI_ARG_EDGE (stmt, PHI_ARG_INDEX_FROM_USE (use));
+             if (e->flags & EDGE_ABNORMAL)
+               {
+                 /* This can only occur for virtual operands, since
+                    for the real ones SSA_NAME_OCCURS_IN_ABNORMAL_PHI (name))
+                    would prevent replacement.  */
+                 gcc_assert (!is_gimple_reg (name));
+                 SSA_NAME_OCCURS_IN_ABNORMAL_PHI (val) = 1;
+               }
            }
        }
-      else
-       VEC_safe_push (tree, heap, stmts, stmt);
-    }
-  /* We do not update the statements in the loop above.  Consider
-     x = w * w;
-
-     If we performed the update in the first loop, the statement
-     would be rescanned after first occurrence of w is replaced,
-     the new uses would be placed to the beginning of the list,
-     and we would never process them.  */
-  for (i = 0; VEC_iterate (tree, stmts, i, stmt); i++)
-    {
-      tree rhs;
-
-      fold_stmt_inplace (stmt);
-
-      rhs = get_rhs (stmt);
-      if (TREE_CODE (rhs) == ADDR_EXPR)
-       recompute_tree_invariant_for_addr_expr (rhs);
+      if (TREE_CODE (stmt) != PHI_NODE)
+       {
+         tree rhs;
 
-      /* If the statement could throw and now cannot, we need to prune cfg.  */
-      if (maybe_clean_or_replace_eh_stmt (stmt, stmt))
-       tree_purge_dead_eh_edges (bb_for_stmt (stmt));
+         fold_stmt_inplace (stmt);
+         rhs = get_rhs (stmt);
+         if (TREE_CODE (rhs) == ADDR_EXPR)
+           recompute_tree_invariant_for_addr_expr (rhs);
 
-      mark_new_vars_to_rename (stmt);
+         maybe_clean_or_replace_eh_stmt (stmt, stmt);
+         mark_new_vars_to_rename (stmt);
+       }
     }
 
-  VEC_free (tree, heap, stmts);
+  gcc_assert (num_imm_uses (name) == 0);
 
   /* Also update the trees stored in loop structures.  */
   if (current_loops)
@@ -1462,24 +1402,23 @@ tree_merge_blocks (basic_block a, basic_block b)
    reached by a complex edge, if there is one.  Else, return BB.  We use
    this in optimizations that use post-dominators for their heuristics,
    to catch the cases in C++ where function calls are involved.  */
-    
+
 basic_block
-single_noncomplex_succ (basic_block bb)  
+single_noncomplex_succ (basic_block bb)
 {
   edge e0, e1;
   if (EDGE_COUNT (bb->succs) != 2)
     return bb;
-   
+
   e0 = EDGE_SUCC (bb, 0);
   e1 = EDGE_SUCC (bb, 1);
   if (e0->flags & EDGE_COMPLEX)
     return e1->dest;
   if (e1->flags & EDGE_COMPLEX)
     return e0->dest;
-   
+
   return bb;
-}       
-        
+}
 
 
 /* Walk the function tree removing unnecessary statements.
@@ -1858,7 +1797,7 @@ remove_useless_stmts_label (tree *stmt_p, struct rus_data *data)
 
 /* If the function is "const" or "pure", then clear TREE_SIDE_EFFECTS on its
    decl.  This allows us to eliminate redundant or useless
-   calls to "const" functions. 
+   calls to "const" functions.
 
    Gimplifier already does the same operation, but we may notice functions
    being const and pure once their calls has been gimplified, so we need
@@ -1972,7 +1911,7 @@ remove_useless_stmts_1 (tree *tp, struct rus_data *data)
                tsi_delink (&i);
                continue;
              }
-           
+
            remove_useless_stmts_1 (tsi_stmt_ptr (i), data);
 
            t = tsi_stmt (i);
@@ -1997,7 +1936,7 @@ remove_useless_stmts_1 (tree *tp, struct rus_data *data)
     }
 }
 
-static void
+static unsigned int
 remove_useless_stmts (void)
 {
   struct rus_data data;
@@ -2010,10 +1949,11 @@ remove_useless_stmts (void)
       remove_useless_stmts_1 (&DECL_SAVED_TREE (current_function_decl), &data);
     }
   while (data.repeat);
+  return 0;
 }
 
 
-struct tree_opt_pass pass_remove_useless_stmts = 
+struct tree_opt_pass pass_remove_useless_stmts =
 {
   "useless",                           /* name */
   NULL,                                        /* gate */
@@ -2114,7 +2054,7 @@ remove_bb (basic_block bb)
              DECL_NONLOCAL (LABEL_EXPR_LABEL (stmt)) = 0;
              FORCED_LABEL (LABEL_EXPR_LABEL (stmt)) = 1;
            }
-                 
+
          new_bb = bb->prev_bb;
          new_bsi = bsi_start (new_bb);
          bsi_remove (&i, false);
@@ -2226,7 +2166,7 @@ find_taken_edge_cond_expr (basic_block bb, tree val)
   edge true_edge, false_edge;
 
   extract_true_false_edges_from_block (bb, &true_edge, &false_edge);
-  
+
   gcc_assert (TREE_CODE (val) == INTEGER_CST);
   return (zero_p (val) ? false_edge : true_edge);
 }
@@ -2326,13 +2266,13 @@ debug_tree_bb_n (int n)
 {
   debug_tree_bb (BASIC_BLOCK (n));
   return BASIC_BLOCK (n);
-}       
+}
 
 
 /* Dump the CFG on stderr.
 
    FLAGS are the same used by the tree dumping functions
-   (see TDF_* in tree.h).  */
+   (see TDF_* in tree-pass.h).  */
 
 void
 debug_tree_cfg (int flags)
@@ -2558,7 +2498,7 @@ is_ctrl_altering_stmt (tree t)
     }
 
   /* OpenMP directives alter control flow.  */
-  if (flag_openmp && OMP_DIRECTIVE_P (t))
+  if (OMP_DIRECTIVE_P (t))
     return true;
 
   /* If a statement can throw, it alters control flow.  */
@@ -2897,7 +2837,7 @@ bsi_insert_after (block_stmt_iterator *i, tree t, enum bsi_iterator_update m)
 
 
 /* Remove the statement pointed to by iterator I.  The iterator is updated
-   to the next statement. 
+   to the next statement.
 
    When REMOVE_EH_INFO is true we remove the statement pointed to by
    iterator I from the EH tables.  Otherwise we do not modify the EH
@@ -2921,18 +2861,18 @@ bsi_remove (block_stmt_iterator *i, bool remove_eh_info)
 
 /* Move the statement at FROM so it comes right after the statement at TO.  */
 
-void 
+void
 bsi_move_after (block_stmt_iterator *from, block_stmt_iterator *to)
 {
   tree stmt = bsi_stmt (*from);
   bsi_remove (from, false);
   bsi_insert_after (to, stmt, BSI_SAME_STMT);
-} 
+}
 
 
 /* Move the statement at FROM so it comes right before the statement at TO.  */
 
-void 
+void
 bsi_move_before (block_stmt_iterator *from, block_stmt_iterator *to)
 {
   tree stmt = bsi_stmt (*from);
@@ -2947,7 +2887,7 @@ void
 bsi_move_to_bb_end (block_stmt_iterator *from, basic_block bb)
 {
   block_stmt_iterator last = bsi_last (bb);
-  
+
   /* Have to check bsi_end_p because it could be an empty block.  */
   if (!bsi_end_p (last) && is_ctrl_stmt (bsi_stmt (last)))
     bsi_move_before (from, &last);
@@ -2959,7 +2899,6 @@ bsi_move_to_bb_end (block_stmt_iterator *from, basic_block bb)
 /* Replace the contents of the statement pointed to by iterator BSI
    with STMT.  If UPDATE_EH_INFO is true, the exception handling
    information of the original statement is moved to the new statement.  */
-  
 
 void
 bsi_replace (const block_stmt_iterator *bsi, tree stmt, bool update_eh_info)
@@ -3010,7 +2949,7 @@ tree_find_edge_insert_loc (edge e, block_stmt_iterator *bsi,
  restart:
 
   /* If the destination has one predecessor which has no PHI nodes,
-     insert there.  Except for the exit block. 
+     insert there.  Except for the exit block.
 
      The requirement for no PHI nodes could be relaxed.  Basically we
      would have to examine the PHIs to prove that none of them used
@@ -3166,7 +3105,7 @@ reinstall_phi_args (edge new_edge, edge old_edge)
 
   if (!PENDING_STMT (old_edge))
     return;
-  
+
   for (var = PENDING_STMT (old_edge), phi = phi_nodes (new_edge->dest);
        var && phi;
        var = TREE_CHAIN (var), phi = PHI_CHAIN (phi))
@@ -3204,13 +3143,12 @@ split_edge_bb_loc (edge edge_in)
 static basic_block
 tree_split_edge (edge edge_in)
 {
-  basic_block new_bb, after_bb, dest, src;
+  basic_block new_bb, after_bb, dest;
   edge new_edge, e;
 
   /* Abnormal edges cannot be split.  */
   gcc_assert (!(edge_in->flags & EDGE_ABNORMAL));
 
-  src = edge_in->src;
   dest = edge_in->dest;
 
   after_bb = split_edge_bb_loc (edge_in);
@@ -3262,7 +3200,7 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
 
   if (TYPE_P (t))
     *walk_subtrees = 0;
-  
+
   /* Check operand N for being valid GIMPLE and give error MSG if not.  */
 #define CHECK_OP(N, MSG) \
   do { if (!is_gimple_val (TREE_OPERAND (t, N)))               \
@@ -3853,11 +3791,11 @@ tree_verify_flow_info (void)
          if (simple_goto_p (stmt))
            {
              error ("explicit goto at end of bb %d", bb->index);
-             err = 1;
+             err = 1;
            }
          else
            {
-             /* FIXME.  We should double check that the labels in the 
+             /* FIXME.  We should double check that the labels in the
                 destination blocks have their address taken.  */
              FOR_EACH_EDGE (e, ei, bb->succs)
                if ((e->flags & (EDGE_FALLTHRU | EDGE_TRUE_VALUE
@@ -4109,7 +4047,7 @@ tree_redirect_edge_and_branch (edge e, basic_block dest)
   if (e->flags & (EDGE_ABNORMAL_CALL | EDGE_EH))
     return NULL;
 
-  if (e->src != ENTRY_BLOCK_PTR 
+  if (e->src != ENTRY_BLOCK_PTR
       && (ret = tree_try_redirect_by_replacing_jump (e, dest)))
     return ret;
 
@@ -4356,7 +4294,7 @@ add_phi_args_after_copy_bb (basic_block bb_copy)
   edge e, e_copy;
   edge_iterator ei;
   tree phi, phi_copy, phi_next, def;
-      
+
   bb = get_bb_original (bb_copy);
 
   FOR_EACH_EDGE (e_copy, ei, bb_copy->succs)
@@ -4518,7 +4456,7 @@ tree_duplicate_sese_region (edge entry, edge exit,
                                       total_count - entry_count,
                                       total_count);
       scale_bbs_frequencies_gcov_type (region_copy, n_region, entry_count,
-                                      total_count);
+                                      total_count);
     }
   else
     {
@@ -4592,6 +4530,7 @@ struct move_stmt_d
   tree from_context;
   tree to_context;
   bitmap vars_to_remove;
+  htab_t new_label_map;
   bool remap_decls_p;
 };
 
@@ -4600,39 +4539,64 @@ struct move_stmt_d
    variable referenced in *TP.  */
 
 static tree
-move_stmt_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, void *data)
+move_stmt_r (tree *tp, int *walk_subtrees, void *data)
 {
   struct move_stmt_d *p = (struct move_stmt_d *) data;
+  tree t = *tp;
 
-  if (p->block && IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (*tp))))
-    TREE_BLOCK (*tp) = p->block;
+  if (p->block && IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (t))))
+    TREE_BLOCK (t) = p->block;
 
-  if (OMP_DIRECTIVE_P (*tp))
+  if (OMP_DIRECTIVE_P (t)
+      && TREE_CODE (t) != OMP_RETURN
+      && TREE_CODE (t) != OMP_CONTINUE)
     {
       /* Do not remap variables inside OMP directives.  Variables
         referenced in clauses and directive header belong to the
         parent function and should not be moved into the child
         function.  */
+      bool save_remap_decls_p = p->remap_decls_p;
       p->remap_decls_p = false;
-    }
+      *walk_subtrees = 0;
+
+      walk_tree (&OMP_BODY (t), move_stmt_r, p, NULL);
 
-  if (p->remap_decls_p
-      && DECL_P (*tp)
-      && DECL_CONTEXT (*tp) == p->from_context)
+      p->remap_decls_p = save_remap_decls_p;
+    }
+  else if (DECL_P (t) && DECL_CONTEXT (t) == p->from_context)
     {
-      DECL_CONTEXT (*tp) = p->to_context;
+      if (TREE_CODE (t) == LABEL_DECL)
+       {
+         if (p->new_label_map)
+           {
+             struct tree_map in, *out;
+             in.from = t;
+             out = htab_find_with_hash (p->new_label_map, &in, DECL_UID (t));
+             if (out)
+               *tp = t = out->to;
+           }
 
-      if (TREE_CODE (*tp) == VAR_DECL)
+         DECL_CONTEXT (t) = p->to_context;
+       }
+      else if (p->remap_decls_p)
        {
-         struct function *f = DECL_STRUCT_FUNCTION (p->to_context);
-         f->unexpanded_var_list = tree_cons (0, *tp, f->unexpanded_var_list);
+         DECL_CONTEXT (t) = p->to_context;
 
-         /* Mark *TP to be removed from the original function,
-            otherwise it will be given a DECL_RTL when the original
-            function is expanded.  */
-         bitmap_set_bit (p->vars_to_remove, DECL_UID (*tp));
+         if (TREE_CODE (t) == VAR_DECL)
+           {
+             struct function *f = DECL_STRUCT_FUNCTION (p->to_context);
+             f->unexpanded_var_list
+               = tree_cons (0, t, f->unexpanded_var_list);
+
+             /* Mark T to be removed from the original function,
+                otherwise it will be given a DECL_RTL when the
+                original function is expanded.  */
+             bitmap_set_bit (p->vars_to_remove, DECL_UID (t));
+           }
        }
     }
+  else if (TYPE_P (t))
+    *walk_subtrees = 0;
 
   return NULL_TREE;
 }
@@ -4644,14 +4608,14 @@ move_stmt_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, void *data)
    original array of blocks and placed in DEST_FN's array of blocks.
    If UPDATE_EDGE_COUNT_P is true, the edge counts on both CFGs is
    updated to reflect the moved edges.
-   
+
    On exit, local variables that need to be removed from
    CFUN->UNEXPANDED_VAR_LIST will have been added to VARS_TO_REMOVE.  */
 
 static void
 move_block_to_fn (struct function *dest_cfun, basic_block bb,
                  basic_block after, bool update_edge_count_p,
-                 bitmap vars_to_remove)
+                 bitmap vars_to_remove, htab_t new_label_map, int eh_offset)
 {
   struct control_flow_graph *cfg;
   edge_iterator ei;
@@ -4702,10 +4666,12 @@ move_block_to_fn (struct function *dest_cfun, basic_block bb,
   for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
     {
       tree stmt = bsi_stmt (si);
+      int region;
 
       d.from_context = cfun->decl;
       d.to_context = dest_cfun->decl;
       d.remap_decls_p = true;
+      d.new_label_map = new_label_map;
       if (TREE_BLOCK (stmt))
        d.block = DECL_INITIAL (dest_cfun->decl);
 
@@ -4737,9 +4703,76 @@ move_block_to_fn (struct function *dest_cfun, basic_block bb,
          if (uid >= dest_cfun->last_label_uid)
            dest_cfun->last_label_uid = uid + 1;
        }
+      else if (TREE_CODE (stmt) == RESX_EXPR && eh_offset != 0)
+       TREE_OPERAND (stmt, 0) =
+         build_int_cst (NULL_TREE,
+                        TREE_INT_CST_LOW (TREE_OPERAND (stmt, 0))
+                        + eh_offset);
+
+      region = lookup_stmt_eh_region (stmt);
+      if (region >= 0)
+       {
+         add_stmt_to_eh_region_fn (dest_cfun, stmt, region + eh_offset);
+         remove_stmt_from_eh_region (stmt);
+       }
+    }
+}
+
+/* Examine the statements in BB (which is in SRC_CFUN); find and return
+   the outermost EH region.  Use REGION as the incoming base EH region.  */
+
+static int
+find_outermost_region_in_block (struct function *src_cfun,
+                               basic_block bb, int region)
+{
+  block_stmt_iterator si;
+
+  for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
+    {
+      tree stmt = bsi_stmt (si);
+      int stmt_region;
+
+      if (TREE_CODE (stmt) == RESX_EXPR)
+       stmt_region = TREE_INT_CST_LOW (TREE_OPERAND (stmt, 0));
+      else
+       stmt_region = lookup_stmt_eh_region_fn (src_cfun, stmt);
+      if (stmt_region > 0)
+       {
+         if (region < 0)
+           region = stmt_region;
+         else if (stmt_region != region)
+           {
+             region = eh_region_outermost (src_cfun, stmt_region, region);
+             gcc_assert (region != -1);
+           }
+       }
     }
+
+  return region;
 }
 
+static tree
+new_label_mapper (tree decl, void *data)
+{
+  htab_t hash = (htab_t) data;
+  struct tree_map *m;
+  void **slot;
+
+  gcc_assert (TREE_CODE (decl) == LABEL_DECL);
+
+  m = xmalloc (sizeof (struct tree_map));
+  m->hash = DECL_UID (decl);
+  m->from = decl;
+  m->to = create_artificial_label ();
+  LABEL_DECL_UID (m->to) = LABEL_DECL_UID (decl);
+
+  slot = htab_find_slot_with_hash (hash, m, m->hash, INSERT);
+  gcc_assert (*slot == NULL);
+
+  *slot = m;
+
+  return m->to;
+}
 
 /* Move a single-entry, single-exit region delimited by ENTRY_BB and
    EXIT_BB to function DEST_CFUN.  The whole region is replaced by a
@@ -4762,11 +4795,12 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
   VEC(basic_block,heap) *bbs;
   basic_block after, bb, *entry_pred, *exit_succ;
   struct function *saved_cfun;
-  int *entry_flag, *exit_flag;
+  int *entry_flag, *exit_flag, eh_offset;
   unsigned i, num_entry_edges, num_exit_edges;
   edge e;
   edge_iterator ei;
   bitmap vars_to_remove;
+  htab_t new_label_map;
 
   saved_cfun = cfun;
 
@@ -4777,7 +4811,8 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
   /* If ENTRY does not strictly dominate EXIT, this cannot be an SESE
      region.  */
   gcc_assert (entry_bb != exit_bb
-              && dominated_by_p (CDI_DOMINATORS, exit_bb, entry_bb));
+              && (!exit_bb
+                 || dominated_by_p (CDI_DOMINATORS, exit_bb, entry_bb)));
 
   bbs = NULL;
   VEC_safe_push (basic_block, heap, bbs, entry_bb);
@@ -4798,21 +4833,52 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
       remove_edge (e);
     }
 
-  num_exit_edges = EDGE_COUNT (exit_bb->succs);
-  exit_succ = (basic_block *) xcalloc (num_exit_edges, sizeof (basic_block));
-  exit_flag = (int *) xcalloc (num_exit_edges, sizeof (int));
-  i = 0;
-  for (ei = ei_start (exit_bb->succs); (e = ei_safe_edge (ei)) != NULL;)
+  if (exit_bb)
     {
-      exit_flag[i] = e->flags;
-      exit_succ[i++] = e->dest;
-      remove_edge (e);
+      num_exit_edges = EDGE_COUNT (exit_bb->succs);
+      exit_succ = (basic_block *) xcalloc (num_exit_edges,
+                                          sizeof (basic_block));
+      exit_flag = (int *) xcalloc (num_exit_edges, sizeof (int));
+      i = 0;
+      for (ei = ei_start (exit_bb->succs); (e = ei_safe_edge (ei)) != NULL;)
+       {
+         exit_flag[i] = e->flags;
+         exit_succ[i++] = e->dest;
+         remove_edge (e);
+       }
+    }
+  else
+    {
+      num_exit_edges = 0;
+      exit_succ = NULL;
+      exit_flag = NULL;
     }
 
   /* Switch context to the child function to initialize DEST_FN's CFG.  */
   gcc_assert (dest_cfun->cfg == NULL);
   cfun = dest_cfun;
+
   init_empty_tree_cfg ();
+
+  /* Initialize EH information for the new function.  */
+  eh_offset = 0;
+  new_label_map = NULL;
+  if (saved_cfun->eh)
+    {
+      int region = -1;
+
+      for (i = 0; VEC_iterate (basic_block, bbs, i, bb); i++)
+       region = find_outermost_region_in_block (saved_cfun, bb, region);
+
+      init_eh_for_function ();
+      if (region != -1)
+       {
+         new_label_map = htab_create (17, tree_map_hash, tree_map_eq, free);
+         eh_offset = duplicate_eh_regions (saved_cfun, new_label_mapper,
+                                           new_label_map, region, 0);
+       }
+    }
+
   cfun = saved_cfun;
 
   /* Move blocks from BBS into DEST_CFUN.  */
@@ -4824,10 +4890,14 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
       /* No need to update edge counts on the last block.  It has
         already been updated earlier when we detached the region from
         the original CFG.  */
-      move_block_to_fn (dest_cfun, bb, after, bb != exit_bb, vars_to_remove);
+      move_block_to_fn (dest_cfun, bb, after, bb != exit_bb, vars_to_remove,
+                       new_label_map, eh_offset);
       after = bb;
     }
 
+  if (new_label_map)
+    htab_delete (new_label_map);
+
   /* Remove the variables marked in VARS_TO_REMOVE from
      CFUN->UNEXPANDED_VAR_LIST.  Otherwise, they will be given a
      DECL_RTL in the context of CFUN.  */
@@ -4861,7 +4931,8 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
      these helpers.  */
   cfun = dest_cfun;
   make_edge (ENTRY_BLOCK_PTR, entry_bb, EDGE_FALLTHRU);
-  make_edge (exit_bb,  EXIT_BLOCK_PTR, 0);
+  if (exit_bb)
+    make_edge (exit_bb,  EXIT_BLOCK_PTR, 0);
   cfun = saved_cfun;
 
   /* Back in the original function, the SESE region has disappeared,
@@ -4873,10 +4944,13 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
   for (i = 0; i < num_exit_edges; i++)
     make_edge (bb, exit_succ[i], exit_flag[i]);
 
-  free (exit_flag);
+  if (exit_bb)
+    {
+      free (exit_flag);
+      free (exit_succ);
+    }
   free (entry_flag);
   free (entry_pred);
-  free (exit_succ);
   free_dominance_info (CDI_DOMINATORS);
   free_dominance_info (CDI_POST_DOMINATORS);
   VEC_free (basic_block, heap, bbs);
@@ -4895,7 +4969,7 @@ dump_function_to_file (tree fn, FILE *file, int flags)
   basic_block bb;
   tree chain;
   struct function *saved_cfun;
-  
+
   fprintf (file, "%s (", lang_hooks.decl_printable_name (fn, 2));
 
   arg = DECL_ARGUMENTS (fn);
@@ -4950,7 +5024,7 @@ dump_function_to_file (tree fn, FILE *file, int flags)
 
       FOR_EACH_BB (bb)
        dump_generic_bb (file, bb, 2, flags);
-       
+
       fprintf (file, "}\n");
       check_bb_profile (EXIT_BLOCK_PTR, file);
     }
@@ -5041,7 +5115,7 @@ print_loop (FILE *file, struct loop *loop, int indent)
 {
   char *s_indent;
   basic_block bb;
-  
+
   if (loop == NULL)
     return;
 
@@ -5051,7 +5125,7 @@ print_loop (FILE *file, struct loop *loop, int indent)
 
   /* Print the loop's header.  */
   fprintf (file, "%sloop_%d\n", s_indent, loop->num);
-  
+
   /* Print the loop's body.  */
   fprintf (file, "%s{\n", s_indent);
   FOR_EACH_BB (bb)
@@ -5063,13 +5137,13 @@ print_loop (FILE *file, struct loop *loop, int indent)
        fprintf (file, "}, succs = {");
        print_succ_bbs (file, bb);
        fprintf (file, "})\n");
-       
+
        /* Print the basic_block's body.  */
        fprintf (file, "%s  {\n", s_indent);
        tree_dump_bb (bb, file, indent + 4);
        fprintf (file, "%s  }\n", s_indent);
       }
-  
+
   print_loop (file, loop->inner, indent + 2);
   fprintf (file, "%s}\n", s_indent);
   print_loop (file, loop->next, indent);
@@ -5079,11 +5153,11 @@ print_loop (FILE *file, struct loop *loop, int indent)
 /* Follow a CFG edge from the entry point of the program, and on entry
    of a loop, pretty print the loop structure on FILE.  */
 
-void 
+void
 print_loop_ir (FILE *file)
 {
   basic_block bb;
-  
+
   bb = BASIC_BLOCK (NUM_FIXED_BLOCKS);
   if (bb && bb->loop_father)
     print_loop (file, bb->loop_father, 0);
@@ -5092,7 +5166,7 @@ print_loop_ir (FILE *file)
 
 /* Debugging loops structure at tree level.  */
 
-void 
+void
 debug_loop_ir (void)
 {
   print_loop_ir (stderr);
@@ -5357,8 +5431,8 @@ tree_execute_on_shrinking_pred (edge e)
    of 'first'. Both of them are dominated by 'new_head' basic block. When
    'new_head' was created by 'second's incoming edge it received phi arguments
    on the edge by split_edge(). Later, additional edge 'e' was created to
-   connect 'new_head' and 'first'. Now this routine adds phi args on this 
-   additional edge 'e' that new_head to second edge received as part of edge 
+   connect 'new_head' and 'first'. Now this routine adds phi args on this
+   additional edge 'e' that new_head to second edge received as part of edge
    splitting.
 */
 
@@ -5376,8 +5450,8 @@ tree_lv_adjust_loop_header_phi (basic_block first, basic_block second,
   /* Browse all 'second' basic block phi nodes and add phi args to
      edge 'e' for 'first' head. PHI args are always in correct order.  */
 
-  for (phi2 = phi_nodes (second), phi1 = phi_nodes (first); 
-       phi2 && phi1; 
+  for (phi2 = phi_nodes (second), phi1 = phi_nodes (first);
+       phi2 && phi1;
        phi2 = PHI_CHAIN (phi2),  phi1 = PHI_CHAIN (phi1))
     {
       tree def = PHI_ARG_DEF (phi2, e2->dest_idx);
@@ -5385,8 +5459,8 @@ tree_lv_adjust_loop_header_phi (basic_block first, basic_block second,
     }
 }
 
-/* Adds a if else statement to COND_BB with condition COND_EXPR.  
-   SECOND_HEAD is the destination of the THEN and FIRST_HEAD is 
+/* Adds a if else statement to COND_BB with condition COND_EXPR.
+   SECOND_HEAD is the destination of the THEN and FIRST_HEAD is
    the destination of the ELSE part.  */
 static void
 tree_lv_add_condition_to_bb (basic_block first_head, basic_block second_head,
@@ -5404,8 +5478,8 @@ tree_lv_add_condition_to_bb (basic_block first_head, basic_block second_head,
   goto2 = build1 (GOTO_EXPR, void_type_node, tree_block_label (second_head));
   new_cond_expr = build3 (COND_EXPR, void_type_node, cond_expr, goto1, goto2);
 
-  /* Add new cond in cond_bb.  */ 
-  bsi = bsi_start (cond_bb); 
+  /* Add new cond in cond_bb.  */
+  bsi = bsi_start (cond_bb);
   bsi_insert_after (&bsi, new_cond_expr, BSI_NEW_STMT);
   /* Adjust edges appropriately to connect new head with first head
      as well as second head.  */
@@ -5442,13 +5516,13 @@ struct cfg_hooks tree_cfg_hooks = {
   tree_lv_add_condition_to_bb, /* lv_add_condition_to_bb */
   tree_lv_adjust_loop_header_phi, /* lv_adjust_loop_header_phi*/
   extract_true_false_edges_from_block, /* extract_cond_bb_edges */
-  flush_pending_stmts          /* flush_pending_stmts */  
+  flush_pending_stmts          /* flush_pending_stmts */
 };
 
 
 /* Split all critical edges.  */
 
-static void
+static unsigned int
 split_critical_edges (void)
 {
   basic_block bb;
@@ -5468,9 +5542,10 @@ split_critical_edges (void)
          }
     }
   end_recording_case_labels ();
+  return 0;
 }
 
-struct tree_opt_pass pass_split_crit_edges = 
+struct tree_opt_pass pass_split_crit_edges =
 {
   "crited",                          /* name */
   NULL,                          /* gate */
@@ -5562,7 +5637,7 @@ gimplify_build1 (block_stmt_iterator *bsi, enum tree_code code, tree type,
 \f
 /* Emit return warnings.  */
 
-static void
+static unsigned int
 execute_warn_function_return (void)
 {
 #ifdef USE_MAPPED_LOCATION
@@ -5635,6 +5710,7 @@ execute_warn_function_return (void)
            }
        }
     }
+  return 0;
 }
 
 
@@ -5681,7 +5757,7 @@ struct tree_opt_pass pass_warn_function_return =
 
 /* Emit noreturn warnings.  */
 
-static void
+static unsigned int
 execute_warn_function_noreturn (void)
 {
   if (warn_missing_noreturn
@@ -5691,6 +5767,7 @@ execute_warn_function_noreturn (void)
     warning (OPT_Wmissing_noreturn, "%Jfunction might be possible candidate "
             "for attribute %<noreturn%>",
             cfun->decl);
+  return 0;
 }
 
 struct tree_opt_pass pass_warn_function_noreturn =