OSDN Git Service

PR middle-end/26084
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 22 Mar 2006 12:50:45 +0000 (12:50 +0000)
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 22 Mar 2006 12:50:45 +0000 (12:50 +0000)
        * except.c (duplicate_eh_regions_0): New.
        (duplicate_eh_region_1): Duplicate the children of the node as
        well as the node itself.  Link them up properly.
        (duplicate_eh_region_2): Merge into ...
        (duplicate_eh_regions): ... here.  Take copy_region argument, and
        copy only a sub-tree if asked.  Simplify copying and fixup.
        (eh_region_outer_p): New.
        * except.h (duplicate_eh_regions): Update decl.
        (eh_region_outer_p): Declare.
        * omp-low.c (lower_omp_single): Fix eh region placement wrt OMP_RETURN.
        (lower_omp_master): Likewise.
        (lower_omp_ordered): Likewise.
        * tree-cfg.c (struct move_stmt_d): Add new_label_map.
        (move_stmt_r): Use it to remap labels.  Handle recursion vs
        remap_decls_p properly.
        (move_block_to_fn): Pass in new_label_map.  Remap RESX_EXPR.
        (find_outermost_region_in_block): New.
        (new_label_mapper): New.
        (move_sese_region_to_fn): Copy eh information to the new function
        properly.
        * tree-inline.c (copy_cfg_body): Update for new duplicate_eh_regions
        argument.
        * tree-pretty-print.c (dump_generic_node): Dump RESX_EXPR region
        number.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@112283 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/except.c
gcc/except.h
gcc/omp-low.c
gcc/tree-cfg.c
gcc/tree-inline.c
gcc/tree-pretty-print.c

index 1f5c7e8..1f564ad 100644 (file)
@@ -1,3 +1,31 @@
+2006-03-22  Richard Henderson  <rth@redhat.com>
+
+       PR middle-end/26084
+       * except.c (duplicate_eh_regions_0): New.
+       (duplicate_eh_region_1): Duplicate the children of the node as
+       well as the node itself.  Link them up properly.
+       (duplicate_eh_region_2): Merge into ...
+       (duplicate_eh_regions): ... here.  Take copy_region argument, and
+       copy only a sub-tree if asked.  Simplify copying and fixup.
+       (eh_region_outer_p): New.
+       * except.h (duplicate_eh_regions): Update decl.
+       (eh_region_outer_p): Declare.
+       * omp-low.c (lower_omp_single): Fix eh region placement wrt OMP_RETURN.
+       (lower_omp_master): Likewise.
+       (lower_omp_ordered): Likewise.
+       * tree-cfg.c (struct move_stmt_d): Add new_label_map.
+       (move_stmt_r): Use it to remap labels.  Handle recursion vs
+       remap_decls_p properly.
+       (move_block_to_fn): Pass in new_label_map.  Remap RESX_EXPR.
+       (find_outermost_region_in_block): New.
+       (new_label_mapper): New.
+       (move_sese_region_to_fn): Copy eh information to the new function
+       properly.
+       * tree-inline.c (copy_cfg_body): Update for new duplicate_eh_regions
+       argument.
+       * tree-pretty-print.c (dump_generic_node): Dump RESX_EXPR region
+       number.
+
 2006-03-22  Richard Sandiford  <richard@codesourcery.com>
 
        * doc/md.texi (-mshared): Mention that -mshared code can be linked
index 7c0088e..01f1108 100644 (file)
@@ -857,84 +857,145 @@ current_function_has_exception_handlers (void)
   return false;
 }
 \f
-static struct eh_region *
-duplicate_eh_region_1 (struct eh_region *o)
-{
-  struct eh_region *n = ggc_alloc_cleared (sizeof (struct eh_region));
-
-  *n = *o;
+/* A subroutine of duplicate_eh_regions.  Search the region tree under O
+   for the miniumum and maximum region numbers.  Update *MIN and *MAX.  */
 
-  n->region_number = o->region_number + cfun->eh->last_region_number;
-  VEC_replace (eh_region, cfun->eh->region_array, n->region_number, n);
-  gcc_assert (!o->aka);
+static void
+duplicate_eh_regions_0 (eh_region o, int *min, int *max)
+{
+  if (o->region_number < *min)
+    *min = o->region_number;
+  if (o->region_number > *max)
+    *max = o->region_number;
 
-  return n;
+  if (o->inner)
+    {
+      o = o->inner;
+      duplicate_eh_regions_0 (o, min, max);
+      while (o->next_peer)
+       {
+         o = o->next_peer;
+         duplicate_eh_regions_0 (o, min, max);
+       }
+    }
 }
 
-static void
-duplicate_eh_region_2 (struct eh_region *o, struct eh_region **n_array,
-                      struct eh_region *prev_try)
+/* A subroutine of duplicate_eh_regions.  Copy the region tree under OLD.
+   Root it at OUTER, and apply EH_OFFSET to the region number.  Don't worry
+   about the other internal pointers just yet, just the tree-like pointers.  */
+
+static eh_region
+duplicate_eh_regions_1 (eh_region old, eh_region outer, int eh_offset)
 {
-  struct eh_region *n = n_array[o->region_number];
+  eh_region ret, n;
 
-  switch (n->type)
-    {
-    case ERT_TRY:
-      if (o->u.try.catch)
-        n->u.try.catch = n_array[o->u.try.catch->region_number];
-      if (o->u.try.last_catch)
-        n->u.try.last_catch = n_array[o->u.try.last_catch->region_number];
-      break;
+  ret = n = ggc_alloc (sizeof (struct eh_region));
 
-    case ERT_CATCH:
-      if (o->u.catch.next_catch)
-       n->u.catch.next_catch = n_array[o->u.catch.next_catch->region_number];
-      if (o->u.catch.prev_catch)
-       n->u.catch.prev_catch = n_array[o->u.catch.prev_catch->region_number];
-      break;
+  *n = *old;
+  n->outer = outer;
+  gcc_assert (!old->aka);
 
-    case ERT_CLEANUP:
-      if (o->u.cleanup.prev_try)
-       n->u.cleanup.prev_try = n_array[o->u.cleanup.prev_try->region_number];
-      else
-        n->u.cleanup.prev_try = prev_try;
-      break;
+  n->region_number += eh_offset;
+  VEC_replace (eh_region, cfun->eh->region_array, n->region_number, n);
 
-    default:
-      break;
+  if (old->inner)
+    {
+      old = old->inner;
+      n = n->inner = duplicate_eh_regions_1 (old, ret, eh_offset);
+      while (old->next_peer)
+       {
+         old = old->next_peer;
+         n = n->next_peer = duplicate_eh_regions_1 (old, ret, eh_offset);
+       }
     }
 
-  if (o->outer)
-    n->outer = n_array[o->outer->region_number];
-  if (o->inner)
-    n->inner = n_array[o->inner->region_number];
-  if (o->next_peer)
-    n->next_peer = n_array[o->next_peer->region_number];
+  return ret;
 }
 
-/* Duplicate the EH regions of IFUN into current function, root the tree in
-   OUTER_REGION and remap labels using MAP callback.  */
+/* Duplicate the EH regions of IFUN, rootted at COPY_REGION, into current
+   function and root the tree below OUTER_REGION.  Remap labels using MAP
+   callback.  The special case of COPY_REGION of 0 means all regions.  */
+
 int
 duplicate_eh_regions (struct function *ifun, duplicate_eh_regions_map map,
-                     void *data, int outer_region)
+                     void *data, int copy_region, int outer_region)
 {
-  int ifun_last_region_number = ifun->eh->last_region_number;
-  struct eh_region **n_array, *root, *cur, *prev_try;
-  int i;
+  eh_region cur, prev_try, outer, *splice;
+  int i, min_region, max_region, eh_offset, cfun_last_region_number;
+  int num_regions;
 
-  if (ifun_last_region_number == 0 || !ifun->eh->region_tree)
+  if (!ifun->eh->region_tree)
     return 0;
 
-  n_array = xcalloc (ifun_last_region_number + 1, sizeof (*n_array));
+  /* Find the range of region numbers to be copied.  The interface we 
+     provide here mandates a single offset to find new number from old,
+     which means we must look at the numbers present, instead of the
+     count or something else.  */
+  if (copy_region > 0)
+    {
+      min_region = INT_MAX;
+      max_region = 0;
+
+      cur = VEC_index (eh_region, ifun->eh->region_array, copy_region);
+      duplicate_eh_regions_0 (cur, &min_region, &max_region);
+    }
+  else
+    min_region = 1, max_region = ifun->eh->last_region_number;
+  num_regions = max_region - min_region + 1;
+  cfun_last_region_number = cfun->eh->last_region_number;
+  eh_offset = cfun_last_region_number + 1 - min_region;
+
+  /* If we've not yet created a region array, do so now.  */
   VEC_safe_grow (eh_region, gc, cfun->eh->region_array,
-                cfun->eh->last_region_number + 1 + ifun_last_region_number);
+                cfun_last_region_number + 1 + num_regions);
+  cfun->eh->last_region_number = max_region + eh_offset;
 
-  /* We might've created new cfun->eh->region_array so zero out nonexisting region 0.  */
+  /* We may have just allocated the array for the first time.
+     Make sure that element zero is null.  */
   VEC_replace (eh_region, cfun->eh->region_array, 0, 0);
 
-  for (i = cfun->eh->last_region_number + 1;
-       i < cfun->eh->last_region_number + 1 + ifun_last_region_number; i++)
-    VEC_replace (eh_region, cfun->eh->region_array, i, 0);
+  /* Zero all entries in the range allocated.  */
+  memset (VEC_address (eh_region, cfun->eh->region_array)
+         + cfun_last_region_number + 1, 0, num_regions);
+
+  /* Locate the spot at which to insert the new tree.  */
+  if (outer_region > 0)
+    {
+      outer = VEC_index (eh_region, cfun->eh->region_array, outer_region);
+      splice = &outer->inner;
+    }
+  else
+    {
+      outer = NULL;
+      splice = &cfun->eh->region_tree;
+    }
+  while (*splice)
+    splice = &(*splice)->next_peer;
+
+  /* Copy all the regions in the subtree.  */
+  if (copy_region > 0)
+    {
+      cur = VEC_index (eh_region, ifun->eh->region_array, copy_region);
+      *splice = duplicate_eh_regions_1 (cur, outer, eh_offset);
+    }
+  else
+    {
+      eh_region n;
+
+      cur = ifun->eh->region_tree;
+      *splice = n = duplicate_eh_regions_1 (cur, outer, eh_offset);
+      while (cur->next_peer)
+       {
+         cur = cur->next_peer;
+         n = n->next_peer = duplicate_eh_regions_1 (cur, outer, eh_offset);
+       }
+    }
+
+  /* Remap all the labels in the new regions.  */
+  for (i = cfun_last_region_number + 1;
+       VEC_iterate (eh_region, cfun->eh->region_array, i, cur); ++i)
+    if (cur && cur->tree_label)
+      cur->tree_label = map (cur->tree_label, data);
 
   /* Search for the containing ERT_TRY region to fix up
      the prev_try short-cuts for ERT_CLEANUP regions.  */
@@ -945,67 +1006,77 @@ duplicate_eh_regions (struct function *ifun, duplicate_eh_regions_map map,
         prev_try = prev_try->outer)
       ;
 
-  for (i = 1; i <= ifun_last_region_number; ++i)
-    {
-      cur = VEC_index (eh_region, ifun->eh->region_array, i);
-      if (!cur || cur->region_number != i)
-       continue;
-      n_array[i] = duplicate_eh_region_1 (cur);
-      if (cur->tree_label)
-       {
-         tree newlabel = map (cur->tree_label, data);
-         n_array[i]->tree_label = newlabel;
-       }
-      else
-       n_array[i]->tree_label = NULL;
-    }
-  for (i = 1; i <= ifun_last_region_number; ++i)
+  /* Remap all of the internal catch and cleanup linkages.  Since we 
+     duplicate entire subtrees, all of the referenced regions will have
+     been copied too.  And since we renumbered them as a block, a simple
+     bit of arithmetic finds us the index for the replacement region.  */
+  for (i = cfun_last_region_number + 1;
+       VEC_iterate (eh_region, cfun->eh->region_array, i, cur); ++i)
     {
-      cur = VEC_index (eh_region, ifun->eh->region_array, i);
-      if (!cur || cur->region_number != i)
+      if (cur == NULL)
        continue;
-      duplicate_eh_region_2 (cur, n_array, prev_try);
-    }
 
-  root = n_array[ifun->eh->region_tree->region_number];
-  gcc_assert (root->outer == NULL);
-  if (outer_region > 0)
-    {
-      struct eh_region *cur
-         = VEC_index (eh_region, cfun->eh->region_array, outer_region);
-      struct eh_region *p = cur->inner;
+#define REMAP(REG) \
+       (REG) = VEC_index (eh_region, cfun->eh->region_array, \
+                          (REG)->region_number + eh_offset)
 
-      if (p)
+      switch (cur->type)
        {
-         while (p->next_peer)
-           p = p->next_peer;
-         p->next_peer = root;
-       }
-      else
-        cur->inner = root;
-      for (i = 1; i <= ifun_last_region_number; ++i)
-       if (n_array[i] && n_array[i]->outer == NULL)
-         n_array[i]->outer = cur;
-    }
-  else
-    {
-      struct eh_region *p = cfun->eh->region_tree;
-      if (p)
-       {
-         while (p->next_peer)
-           p = p->next_peer;
-         p->next_peer = root;
+       case ERT_TRY:
+         if (cur->u.try.catch)
+           REMAP (cur->u.try.catch);
+         if (cur->u.try.last_catch)
+           REMAP (cur->u.try.last_catch);
+         break;
+
+       case ERT_CATCH:
+         if (cur->u.catch.next_catch)
+           REMAP (cur->u.catch.next_catch);
+         if (cur->u.catch.prev_catch)
+           REMAP (cur->u.catch.prev_catch);
+         break;
+
+       case ERT_CLEANUP:
+         if (cur->u.cleanup.prev_try)
+           REMAP (cur->u.cleanup.prev_try);
+         else
+           cur->u.cleanup.prev_try = prev_try;
+         break;
+
+       default:
+         break;
        }
-      else
-        cfun->eh->region_tree = root;
+
+#undef REMAP
     }
 
-  free (n_array);
+  return eh_offset;
+}
 
-  i = cfun->eh->last_region_number;
-  cfun->eh->last_region_number = i + ifun_last_region_number;
+/* Return true if REGION_A is outer to REGION_B in IFUN.  */
 
-  return i;
+bool
+eh_region_outer_p (struct function *ifun, int region_a, int region_b)
+{
+  struct eh_region *rp_a, *rp_b;
+
+  gcc_assert (ifun->eh->last_region_number > 0);
+  gcc_assert (ifun->eh->region_tree);
+
+  rp_a = VEC_index (eh_region, ifun->eh->region_array, region_a);
+  rp_b = VEC_index (eh_region, ifun->eh->region_array, region_b);
+  gcc_assert (rp_a != NULL);
+  gcc_assert (rp_b != NULL);
+
+  do
+    {
+      if (rp_a == rp_b)
+       return true;
+      rp_b = rp_b->outer;
+    }
+  while (rp_b);
+
+  return false;
 }
 \f
 static int
index 46914d4..5b28296 100644 (file)
@@ -82,7 +82,8 @@ extern rtx expand_builtin_extend_pointer (tree);
 extern rtx get_exception_pointer (struct function *);
 extern rtx get_exception_filter (struct function *);
 typedef tree (*duplicate_eh_regions_map) (tree, void *);
-extern int duplicate_eh_regions (struct function *, duplicate_eh_regions_map, void *, int);
+extern int duplicate_eh_regions (struct function *, duplicate_eh_regions_map,
+                                void *, int, int);
 
 extern void sjlj_emit_function_exit_after (rtx);
 extern void default_init_unwind_resume_libfunc (void);
@@ -106,6 +107,7 @@ extern void collect_eh_region_array (void);
 extern void expand_resx_expr (tree);
 extern void verify_eh_tree (struct function *);
 extern void dump_eh_tree (FILE *, struct function *);
+extern bool eh_region_outer_p (struct function *, int, int);
 
 /* tree-eh.c */
 extern void add_stmt_to_eh_region_fn (struct function *, tree, int);
index 65f7151..41b4093 100644 (file)
@@ -3464,6 +3464,9 @@ lower_omp_sections (tree *stmt_p, omp_context *ctx)
   new_body = alloc_stmt_list ();
   append_to_statement_list (ilist, &new_body);
   append_to_statement_list (stmt, &new_body);
+  /* ??? The OMP_RETURN doesn't logically belong here, but in
+     expand_omp_sections we expect this marker to be where the
+     individual sections join after completing the loop.  */
   append_to_statement_list (region_exit, &new_body);
   append_to_statement_list (olist, &new_body);
   append_to_statement_list (dlist, &new_body);
@@ -3610,9 +3613,9 @@ lower_omp_single (tree *stmt_p, omp_context *ctx)
     lower_omp_single_simple (single_stmt, &BIND_EXPR_BODY (bind));
 
   append_to_statement_list (dlist, &BIND_EXPR_BODY (bind));
+  maybe_catch_exception (&BIND_EXPR_BODY (bind));
   t = make_node (OMP_RETURN_EXPR);
   append_to_statement_list (t, &BIND_EXPR_BODY (bind));
-  maybe_catch_exception (&BIND_EXPR_BODY (bind));
   pop_gimplify_context (bind);
 
   BIND_EXPR_VARS (bind) = chainon (BIND_EXPR_VARS (bind), ctx->block_vars);
@@ -3647,9 +3650,9 @@ lower_omp_master (tree *stmt_p, omp_context *ctx)
 
   x = build1 (LABEL_EXPR, void_type_node, lab);
   gimplify_and_add (x, &BIND_EXPR_BODY (bind));
+  maybe_catch_exception (&BIND_EXPR_BODY (bind));
   x = make_node (OMP_RETURN_EXPR);
   append_to_statement_list (x, &BIND_EXPR_BODY (bind));
-  maybe_catch_exception (&BIND_EXPR_BODY (bind));
   pop_gimplify_context (bind);
 
   BIND_EXPR_VARS (bind) = chainon (BIND_EXPR_VARS (bind), ctx->block_vars);
@@ -3683,9 +3686,9 @@ lower_omp_ordered (tree *stmt_p, omp_context *ctx)
   x = built_in_decls[BUILT_IN_GOMP_ORDERED_END];
   x = build_function_call_expr (x, NULL);
   gimplify_and_add (x, &BIND_EXPR_BODY (bind));
+  maybe_catch_exception (&BIND_EXPR_BODY (bind));
   x = make_node (OMP_RETURN_EXPR);
   append_to_statement_list (x, &BIND_EXPR_BODY (bind));
-  maybe_catch_exception (&BIND_EXPR_BODY (bind));
   pop_gimplify_context (bind);
 
   BIND_EXPR_VARS (bind) = chainon (BIND_EXPR_VARS (bind), ctx->block_vars);
index b7f147c..6f0e947 100644 (file)
@@ -4591,6 +4591,7 @@ struct move_stmt_d
   tree from_context;
   tree to_context;
   bitmap vars_to_remove;
+  htab_t new_label_map;
   bool remap_decls_p;
 };
 
@@ -4599,39 +4600,62 @@ 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_EXPR)
     {
       /* 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;
 }
@@ -4650,7 +4674,7 @@ move_stmt_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, void *data)
 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;
@@ -4701,10 +4725,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);
 
@@ -4736,11 +4762,66 @@ 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;
 
-      remove_stmt_from_eh_region (stmt);
+      stmt_region = lookup_stmt_eh_region_fn (src_cfun, stmt);
+      if (stmt_region > 0
+         && (region < 0 || eh_region_outer_p (src_cfun, stmt_region, region)))
+       region = stmt_region;
     }
+
+  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
@@ -4763,11 +4844,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;
 
@@ -4813,7 +4895,28 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
   /* 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.  */
@@ -4825,10 +4928,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.  */
index 8d258ff..3e35842 100644 (file)
@@ -924,7 +924,8 @@ copy_cfg_body (copy_body_data * id, gcov_type count, int frequency,
       if (id->transform_new_cfg)
         init_eh_for_function ();
       id->eh_region_offset
-       = duplicate_eh_regions (cfun_to_copy, remap_decl_1, id, id->eh_region);
+       = duplicate_eh_regions (cfun_to_copy, remap_decl_1, id,
+                               0, id->eh_region);
     }
   /* Use aux pointers to map the original blocks to copy.  */
   FOR_EACH_BB_FN (bb, cfun_to_copy)
index 23bea83..a8a33a5 100644 (file)
@@ -1557,8 +1557,8 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
       break;
 
     case RESX_EXPR:
-      pp_string (buffer, "resx");
-      /* ??? Any sensible way to present the eh region?  */
+      pp_string (buffer, "resx ");
+      dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
       break;
 
     case ASM_EXPR: