OSDN Git Service

* tree.c (list_equal_p): New function.
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 25 Apr 2009 18:27:19 +0000 (18:27 +0000)
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 25 Apr 2009 18:27:19 +0000 (18:27 +0000)
* tree.h (list_equal_p): Declare.
* coretypes.h (edge_def, edge, const_edge, basic_block_def
basic_block_def, basic_block, const_basic_block): New.
* tree-eh.c (make_eh_edge): EH edges are not abnormal.
(redirect_eh_edge): New function.
(make_eh_edge_update_phi): EH edges are not abnormal.
* except.c: Include tree-flow.h.
(list_match): New function.
(eh_region_replaceable_by_p): New function.
(replace_region): New function.
(hash_type_list): New function.
(hash_eh_region): New function.
(eh_regions_equal_p): New function.
(merge_peers): New function.
(remove_unreachable_regions): Verify EH tree when checking;
merge peers.
(copy_eh_region_1): New function.
(copy_eh_region): New function.
(push_reachable_handler): New function.
(build_post_landing_pads, dw2_build_landing_pads): Be ready for
regions without label but with live RESX.
* except.h (redirect_eh_edge_to_label): New.
* tree-flow.h (redirect_eh_edge): New.
* coretypes.h (edge_def, edge, const_edge, basic_block_def
basic_block_def, basic_block, const_basic_block): Remove.
* Makefile.in (except.o): Add dependency on tree-flow.h
* tree-cfg.c (gimple_redirect_edge_and_branch): Handle EH edges.
* basic-block.h (edge, const_edge, basic_block, const_basic_block):
Remove.

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

13 files changed:
gcc/ChangeLog
gcc/Makefile.in
gcc/basic-block.h
gcc/coretypes.h
gcc/except.c
gcc/except.h
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/tree-ssa/ehcleanup-1.C
gcc/tree-cfg.c
gcc/tree-eh.c
gcc/tree-flow.h
gcc/tree.c
gcc/tree.h

index 6d2ae22..47f98fa 100644 (file)
@@ -1,3 +1,36 @@
+2009-04-25  Jan Hubicka  <jh@suse.cz>
+
+       * tree.c (list_equal_p): New function.
+       * tree.h (list_equal_p): Declare.
+       * coretypes.h (edge_def, edge, const_edge, basic_block_def
+       basic_block_def, basic_block, const_basic_block): New.
+       * tree-eh.c (make_eh_edge): EH edges are not abnormal.
+       (redirect_eh_edge): New function.
+       (make_eh_edge_update_phi): EH edges are not abnormal.
+       * except.c: Include tree-flow.h.
+       (list_match): New function.
+       (eh_region_replaceable_by_p): New function.
+       (replace_region): New function.
+       (hash_type_list): New function.
+       (hash_eh_region): New function.
+       (eh_regions_equal_p): New function.
+       (merge_peers): New function.
+       (remove_unreachable_regions): Verify EH tree when checking;
+       merge peers.
+       (copy_eh_region_1): New function.
+       (copy_eh_region): New function.
+       (push_reachable_handler): New function.
+       (build_post_landing_pads, dw2_build_landing_pads): Be ready for
+       regions without label but with live RESX.
+       * except.h (redirect_eh_edge_to_label): New.
+       * tree-flow.h (redirect_eh_edge): New.
+       * coretypes.h (edge_def, edge, const_edge, basic_block_def
+       basic_block_def, basic_block, const_basic_block): Remove.
+       * Makefile.in (except.o): Add dependency on tree-flow.h
+       * tree-cfg.c (gimple_redirect_edge_and_branch): Handle EH edges.
+       * basic-block.h (edge, const_edge, basic_block, const_basic_block):
+       Remove.
+
 2009-04-25  Eric Botcazou  <ebotcazou@adacore.com>
 
        PR bootstrap/39645
index 743cf10..8b97805 100644 (file)
@@ -2525,7 +2525,7 @@ except.o : except.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
    langhooks.h insn-config.h hard-reg-set.h $(BASIC_BLOCK_H) output.h \
    dwarf2asm.h dwarf2out.h $(TOPLEV_H) $(HASHTAB_H) intl.h $(GGC_H) \
    gt-$(EXCEPT_H) $(CGRAPH_H) $(INTEGRATE_H) $(DIAGNOSTIC_H) dwarf2.h \
-   $(TARGET_H) $(TM_P_H) $(TREE_PASS_H) $(TIMEVAR_H)
+   $(TARGET_H) $(TM_P_H) $(TREE_PASS_H) $(TIMEVAR_H) $(TREE_FLOW_H)
 expr.o : expr.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
    $(TREE_H) $(FLAGS_H) $(FUNCTION_H) $(REGS_H) $(EXPR_H) $(OPTABS_H) \
    libfuncs.h $(INSN_ATTR_H) insn-config.h $(RECOG_H) output.h \
index da262ac..19ccd48 100644 (file)
@@ -147,8 +147,6 @@ struct GTY(()) edge_def {
                                   in profile.c  */
 };
 
-typedef struct edge_def *edge;
-typedef const struct edge_def *const_edge;
 DEF_VEC_P(edge);
 DEF_VEC_ALLOC_P(edge,gc);
 DEF_VEC_ALLOC_P(edge,heap);
@@ -277,9 +275,6 @@ struct GTY(()) gimple_bb_info {
   gimple_seq phi_nodes;
 };
 
-typedef struct basic_block_def *basic_block;
-typedef const struct basic_block_def *const_basic_block;
-
 DEF_VEC_P(basic_block);
 DEF_VEC_ALLOC_P(basic_block,gc);
 DEF_VEC_ALLOC_P(basic_block,heap);
index a04953e..11583ff 100644 (file)
@@ -97,6 +97,12 @@ enum tls_model {
   TLS_MODEL_LOCAL_EXEC
 };
 
+struct edge_def;
+typedef struct edge_def *edge;
+typedef const struct edge_def *const_edge;
+struct basic_block_def;
+typedef struct basic_block_def *basic_block;
+typedef const struct basic_block_def *const_basic_block;
 #else
 
 struct _dont_use_rtx_here_;
index 599ad6f..5b8ed7c 100644 (file)
@@ -77,6 +77,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "diagnostic.h"
 #include "tree-pass.h"
 #include "timevar.h"
+#include "tree-flow.h"
 
 /* Provide defaults for stuff that may not be defined when using
    sjlj exceptions.  */
@@ -628,6 +629,238 @@ bring_to_root (struct eh_region *r)
   cfun->eh->region_tree = r;
 }
 
+/* Return true if region R2 can be replaced by R1.  */
+
+static bool
+eh_region_replaceable_by_p (const struct eh_region *r1,
+                           const struct eh_region *r2)
+{
+  /* Regions are semantically same if they are of same type,
+     have same label and type.  */
+  if (r1->type != r2->type)
+    return false;
+  if (r1->tree_label != r2->tree_label)
+    return false;
+
+  /* Verify that also region type dependent data are the same.  */
+  switch (r1->type)
+    {
+      case ERT_MUST_NOT_THROW:
+      case ERT_CLEANUP:
+       break;
+      case ERT_TRY:
+       {
+         struct eh_region *c1, *c2;
+         for (c1 = r1->u.eh_try.eh_catch,
+              c2 = r2->u.eh_try.eh_catch;
+              c1 && c2;
+              c1 = c1->u.eh_catch.next_catch,
+              c2 = c2->u.eh_catch.next_catch)
+           if (!eh_region_replaceable_by_p (c1, c2))
+             return false;
+         if (c1 || c2)
+           return false;
+        }
+       break;
+      case ERT_CATCH:
+        if (!list_equal_p (r1->u.eh_catch.type_list, r2->u.eh_catch.type_list))
+         return false;
+        if (!list_equal_p (r1->u.eh_catch.filter_list,
+                          r2->u.eh_catch.filter_list))
+         return false;
+        break;
+      case ERT_ALLOWED_EXCEPTIONS:
+        if (!list_equal_p (r1->u.allowed.type_list, r2->u.allowed.type_list))
+         return false;
+       if (r1->u.allowed.filter != r2->u.allowed.filter)
+         return false;
+       break;
+      case ERT_THROW:
+       if (r1->u.eh_throw.type != r2->u.eh_throw.type)
+         return false;
+       break;
+      default:
+        gcc_unreachable ();
+    }
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    fprintf (dump_file, "Regions %i and %i match\n", r1->region_number,
+                                                    r2->region_number);
+  return true;
+}
+
+/* Replace region R2 by R1.  */
+
+static void
+replace_region (struct eh_region *r1, struct eh_region *r2)
+{
+  struct eh_region *next1 = r1->u.eh_try.eh_catch;
+  struct eh_region *next2 = r2->u.eh_try.eh_catch;
+  bool is_try = r1->type == ERT_TRY;
+
+  gcc_assert (r1->type != ERT_CATCH);
+  remove_eh_handler_and_replace (r2, r1, false);
+  if (is_try)
+    {
+      while (next1)
+       {
+         r1 = next1;
+         r2 = next2;
+         gcc_assert (next1->type == ERT_CATCH);
+         gcc_assert (next2->type == ERT_CATCH);
+         next1 = next1->u.eh_catch.next_catch;
+         next2 = next2->u.eh_catch.next_catch;
+         remove_eh_handler_and_replace (r2, r1, false);
+       }
+    }
+}
+
+/* Return hash value of type list T.  */
+
+static hashval_t
+hash_type_list (tree t)
+{
+  hashval_t val = 0;
+  for (; t; t = TREE_CHAIN (t))
+    val = iterative_hash_hashval_t (TREE_HASH (TREE_VALUE (t)), val);
+  return val;
+}
+
+/* Hash EH regions so semantically same regions get same hash value.  */
+
+static hashval_t
+hash_eh_region (const void *r)
+{
+  const struct eh_region *region = (const struct eh_region *)r;
+  hashval_t val = region->type;
+
+  if (region->tree_label)
+    val = iterative_hash_hashval_t (LABEL_DECL_UID (region->tree_label), val);
+  switch (region->type)
+    {
+      case ERT_MUST_NOT_THROW:
+      case ERT_CLEANUP:
+       break;
+      case ERT_TRY:
+       {
+         struct eh_region *c;
+         for (c = region->u.eh_try.eh_catch;
+              c; c = c->u.eh_catch.next_catch)
+           val = iterative_hash_hashval_t (hash_eh_region (c), val);
+        }
+       break;
+      case ERT_CATCH:
+        val = iterative_hash_hashval_t (hash_type_list
+                                         (region->u.eh_catch.type_list), val);
+        break;
+      case ERT_ALLOWED_EXCEPTIONS:
+        val = iterative_hash_hashval_t
+               (hash_type_list (region->u.allowed.type_list), val);
+        val = iterative_hash_hashval_t (region->u.allowed.filter, val);
+       break;
+      case ERT_THROW:
+        val |= iterative_hash_hashval_t (TYPE_UID (region->u.eh_throw.type), val);
+       break;
+      default:
+        gcc_unreachable ();
+    }
+  return val;
+}
+
+/* Return true if regions R1 and R2 are equal.  */
+
+static int
+eh_regions_equal_p (const void *r1, const void *r2)
+{
+  return eh_region_replaceable_by_p ((const struct eh_region *)r1,
+                                    (const struct eh_region *)r2);
+}
+
+/* Walk all peers of REGION and try to merge those regions
+   that are semantically equivalent.  Look into subregions
+   recursively too.  */
+
+static bool
+merge_peers (struct eh_region *region)
+{
+  struct eh_region *r1, *r2, *outer = NULL, *next;
+  bool merged = false;
+  int num_regions = 0;
+  if (region)
+    outer = region->outer;
+  else
+    return false;
+
+  /* First see if there is inner region equivalent to region
+     in question.  EH control flow is acyclic so we know we
+     can merge them.  */
+  if (outer)
+    for (r1 = region; r1; r1 = next)
+      {
+        next = r1->next_peer;
+       if (r1->type == ERT_CATCH)
+         continue;
+        if (eh_region_replaceable_by_p (r1->outer, r1))
+         {
+           replace_region (r1->outer, r1);
+           merged = true;
+         }
+       else
+         num_regions ++;
+      }
+
+  /* Get new first region and try to match the peers
+     for equivalence.  */
+  if (outer)
+    region = outer->inner;
+  else
+    region = cfun->eh->region_tree;
+
+  /* There are few regions to inspect:
+     N^2 loop matching each region with each region
+     will do the job well.  */
+  if (num_regions < 10)
+    {
+      for (r1 = region; r1; r1 = r1->next_peer)
+       {
+         if (r1->type == ERT_CATCH)
+           continue;
+         for (r2 = r1->next_peer; r2; r2 = next)
+           {
+             next = r2->next_peer;
+             if (eh_region_replaceable_by_p (r1, r2))
+               {
+                 replace_region (r1, r2);
+                 merged = true;
+               }
+           }
+       }
+    }
+  /* Or use hashtable to avoid N^2 behaviour.  */
+  else
+    {
+      htab_t hash;
+      hash = htab_create (num_regions, hash_eh_region,
+                         eh_regions_equal_p, NULL);
+      for (r1 = region; r1; r1 = next)
+       {
+          void **slot;
+
+         next = r1->next_peer;
+         if (r1->type == ERT_CATCH)
+           continue;
+         slot = htab_find_slot (hash, r1, INSERT);
+         if (!*slot)
+           *slot = r1;
+         else
+           replace_region ((struct eh_region *)*slot, r1);
+       }
+      htab_delete (hash);
+    }
+  for (r1 = region; r1; r1 = r1->next_peer)
+    merged |= merge_peers (r1->inner);
+  return merged;
+}
+
 /* Remove all regions whose labels are not reachable.
    REACHABLE is bitmap of all regions that are used by the function
    CONTAINS_STMT is bitmap of all regions that contains stmt (or NULL). */
@@ -748,6 +981,7 @@ remove_unreachable_regions (sbitmap reachable, sbitmap contains_stmt)
       else
        bring_to_root (r);
     }
+  merge_peers (cfun->eh->region_tree);
 #ifdef ENABLE_CHECKING
   verify_eh_tree (cfun);
 #endif
@@ -1140,6 +1374,238 @@ duplicate_eh_regions (struct function *ifun, duplicate_eh_regions_map map,
   return eh_offset;
 }
 
+/* Return new copy of eh region OLD inside region NEW_OUTER.
+   Do not care about updating the tree otherwise.  */
+
+static struct eh_region *
+copy_eh_region_1 (struct eh_region *old, struct eh_region *new_outer)
+{
+  struct eh_region *new_eh = gen_eh_region (old->type, new_outer);
+  new_eh->u = old->u;
+  new_eh->tree_label = old->tree_label;
+  new_eh->may_contain_throw = old->may_contain_throw;
+  VEC_safe_grow (eh_region, gc, cfun->eh->region_array,
+                cfun->eh->last_region_number + 1);
+  VEC_replace (eh_region, cfun->eh->region_array, new_eh->region_number, new_eh);
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    fprintf (dump_file, "Copying region %i to %i\n", old->region_number, new_eh->region_number);
+  return new_eh;
+}
+
+/* Return new copy of eh region OLD inside region NEW_OUTER.  
+  
+   Copy whole catch-try chain if neccesary and update cleanup region prev_try
+   pointers.
+
+   PREV_TRY_MAP points to outer TRY region if it was copied in trace already.  */
+
+static struct eh_region *
+copy_eh_region (struct eh_region *old, struct eh_region *new_outer,
+               struct eh_region *prev_try_map)
+{
+  struct eh_region *r, *n, *old_try, *new_try, *ret = NULL;
+  VEC(eh_region,heap) *catch_list = NULL;
+
+  if (old->type != ERT_CATCH)
+    {
+      gcc_assert (old->type != ERT_TRY);
+      r = copy_eh_region_1 (old, new_outer);
+      if (r->type == ERT_CLEANUP && prev_try_map)
+        {
+         gcc_assert (r->u.cleanup.prev_try);
+          r->u.cleanup.prev_try = prev_try_map;
+       }
+      return r;
+    }
+
+  /* Locate and copy corresponding TRY.  */
+  for (old_try = old->next_peer; old_try->type == ERT_CATCH; old_try = old_try->next_peer)
+    continue;
+  gcc_assert (old_try->type == ERT_TRY);
+  new_try = gen_eh_region_try (new_outer);
+  new_try->tree_label = old_try->tree_label;
+  new_try->may_contain_throw = old_try->may_contain_throw;
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    fprintf (dump_file, "Copying try-catch regions. Try: %i to %i\n",
+            old_try->region_number, new_try->region_number);
+  VEC_safe_grow (eh_region, gc, cfun->eh->region_array,
+                cfun->eh->last_region_number + 1);
+  VEC_replace (eh_region, cfun->eh->region_array, new_try->region_number, new_try);
+
+  /* In order to keep CATCH list in order, we need to copy in reverse order.  */
+  for (r = old_try->u.eh_try.last_catch; r->type == ERT_CATCH; r = r->next_peer)
+    VEC_safe_push (eh_region, heap, catch_list, r);
+
+  while (VEC_length (eh_region, catch_list))
+    {
+      r = VEC_pop (eh_region, catch_list);
+
+      /* Duplicate CATCH.  */
+      n = gen_eh_region_catch (new_try, r->u.eh_catch.type_list);
+      n->tree_label = r->tree_label;
+      n->may_contain_throw = r->may_contain_throw;
+      VEC_safe_grow (eh_region, gc, cfun->eh->region_array,
+                    cfun->eh->last_region_number + 1);
+      VEC_replace (eh_region, cfun->eh->region_array, n->region_number, n);
+      n->tree_label = r->tree_label;
+
+      if (dump_file && (dump_flags & TDF_DETAILS))
+        fprintf (dump_file, "Copying try-catch regions. Catch: %i to %i\n",
+                r->region_number, n->region_number);
+      if (r == old)
+       ret = n;
+    }
+  VEC_free (eh_region, heap, catch_list);
+  gcc_assert (ret);
+  return ret;
+}
+
+/* Callback for forach_reachable_handler that push REGION into single VECtor DATA.  */
+
+static void
+push_reachable_handler (struct eh_region *region, void *data)
+{
+  VEC(eh_region,heap) **trace = (VEC(eh_region,heap) **) data;
+  VEC_safe_push (eh_region, heap, *trace, region);
+}
+
+/* Redirect EH edge E that to NEW_DEST_LABEL.
+   IS_RESX, INLINABLE_CALL and REGION_NMUBER match the parameter of
+   foreach_reachable_handler.  */
+
+struct eh_region *
+redirect_eh_edge_to_label (edge e, tree new_dest_label, bool is_resx,
+                          bool inlinable_call, int region_number)
+{
+  struct eh_region *outer, *prev_try_map = NULL;
+  struct eh_region *region;
+  VEC (eh_region, heap) * trace = NULL;
+  int i;
+  int start_here = -1;
+  basic_block old_bb = e->dest;
+  struct eh_region *old, *r = NULL;
+  bool update_inplace = true;
+  edge_iterator ei;
+  edge e2;
+
+  /* If there is only one EH edge, we don't need to duplicate;
+     just update labels in the tree.  */
+  FOR_EACH_EDGE (e2, ei, old_bb->preds)
+    if ((e2->flags & EDGE_EH) && e2 != e)
+      {
+        update_inplace = false;
+        break;
+      }
+
+  region = VEC_index (eh_region, cfun->eh->region_array, region_number);
+  gcc_assert (region);
+
+  foreach_reachable_handler (region_number, is_resx, inlinable_call,
+                            push_reachable_handler, &trace);
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      dump_eh_tree (dump_file, cfun);
+      fprintf (dump_file, "Trace: ");
+      for (i = 0; i < (int) VEC_length (eh_region, trace); i++)
+       fprintf (dump_file, " %i", VEC_index (eh_region, trace, i)->region_number);
+      fprintf (dump_file, " inplace: %i\n", update_inplace);
+    }
+
+  if (update_inplace)
+    {
+      /* In easy route just walk trace and update all occurences of the label.  */
+      for (i = 0; i < (int) VEC_length (eh_region, trace); i++)
+       {
+         r = VEC_index (eh_region, trace, i);
+         if (r->tree_label && label_to_block (r->tree_label) == old_bb)
+           {
+             r->tree_label = new_dest_label;
+             if (dump_file && (dump_flags & TDF_DETAILS))
+               fprintf (dump_file, "Updating label for region %i\n",
+                        r->region_number);
+           }
+       }
+      r = region;
+    }
+  else
+    {
+      /* Now look for outermost handler that reffers to the basic block in question.
+         We start our duplication there.  */
+      for (i = 0; i < (int) VEC_length (eh_region, trace); i++)
+       {
+         r = VEC_index (eh_region, trace, i);
+         if (r->tree_label && label_to_block (r->tree_label) == old_bb)
+           start_here = i;
+       }
+      outer = VEC_index (eh_region, trace, start_here)->outer;
+      gcc_assert (start_here >= 0);
+
+      /* And now do the dirty job!  */
+      for (i = start_here; i >= 0; i--)
+       {
+         old = VEC_index (eh_region, trace, i);
+         gcc_assert (!outer || old->outer != outer->outer);
+
+         /* Copy region and update label.  */
+         r = copy_eh_region (old, outer, prev_try_map);
+         VEC_replace (eh_region, trace, i, r);
+         if (r->tree_label && label_to_block (r->tree_label) == old_bb)
+           {
+             r->tree_label = new_dest_label;
+             if (dump_file && (dump_flags & TDF_DETAILS))
+               fprintf (dump_file, "Updating label for region %i\n",
+                        r->region_number);
+           }
+
+         /* We got into copying CATCH.  copy_eh_region already did job
+            of copying all catch blocks corresponding to the try.  Now
+            we need to update labels in all of them and see trace.
+
+            We continue nesting into TRY region corresponding to CATCH:
+            When duplicating EH tree contaiing subregions of CATCH,
+            the CATCH region itself is never inserted to trace so we
+            never get here anyway.  */
+         if (r->type == ERT_CATCH)
+           {
+             /* Walk other catch regions we copied and update labels as needed.  */
+             for (r = r->next_peer; r->type == ERT_CATCH; r = r->next_peer)
+               if (r->tree_label && label_to_block (r->tree_label) == old_bb)
+                 {
+                   r->tree_label = new_dest_label;
+                   if (dump_file && (dump_flags & TDF_DETAILS))
+                     fprintf (dump_file, "Updating label for region %i\n",
+                              r->region_number);
+                 }
+              gcc_assert (r->type == ERT_TRY);
+
+              /* Skip sibling catch regions from the trace.
+                 They are already updated.  */
+              while (i > 0 && VEC_index (eh_region, trace, i - 1)->outer == old->outer)
+                {
+                  gcc_assert (VEC_index (eh_region, trace, i - 1)->type == ERT_CATCH);
+                  i--;
+                }
+            }
+
+         /* Cleanup regions points to outer TRY blocks.  */
+         if (r->type == ERT_TRY)
+           prev_try_map = r;
+         outer = r;
+       }
+        
+      if (is_resx || region->type == ERT_THROW)
+       r = copy_eh_region (region, outer, prev_try_map);
+    }
+
+  VEC_free (eh_region, heap, trace);
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      dump_eh_tree (dump_file, cfun);
+      fprintf (dump_file, "New region: %i\n", r->region_number);
+    }
+  return r;
+}
+
 /* Return region number of region that is outer to both if REGION_A and
    REGION_B in IFUN.  */
 
@@ -1478,6 +1944,12 @@ build_post_landing_pads (void)
       switch (region->type)
        {
        case ERT_TRY:
+         /* It is possible that TRY region is kept alive only because some of
+            contained catch region still have RESX instruction but they are
+            reached via their copies.  In this case we need to do nothing.  */
+         if (!region->u.eh_try.eh_catch->label)
+           break;
+
          /* ??? Collect the set of all non-overlapping catch handlers
               all the way up the chain until blocked by a cleanup.  */
          /* ??? Outer try regions can share landing pads with inner
@@ -1537,6 +2009,8 @@ build_post_landing_pads (void)
          break;
 
        case ERT_ALLOWED_EXCEPTIONS:
+         if (!region->label)
+           break;
          region->post_landing_pad = gen_label_rtx ();
 
          start_sequence ();
@@ -1679,6 +2153,9 @@ dw2_build_landing_pads (void)
          && region->type != ERT_ALLOWED_EXCEPTIONS)
        continue;
 
+      if (!region->post_landing_pad)
+       continue;
+
       start_sequence ();
 
       region->landing_pad = gen_label_rtx ();
index 14a263a..50d6b31 100644 (file)
@@ -278,4 +278,5 @@ extern void set_eh_throw_stmt_table (struct function *, struct htab *);
 extern void remove_unreachable_regions (sbitmap, sbitmap);
 extern VEC(int,heap) * label_to_region_map (void);
 extern int num_eh_regions (void);
+extern struct eh_region *redirect_eh_edge_to_label (struct edge_def *, tree, bool, bool, int);
 extern int get_next_region_sharing_label (int);
index af9f6bc..c05006b 100644 (file)
@@ -1,3 +1,7 @@
+2009-04-25  Jan Hubicka  <jh@suse.cz>
+
+       * g++.dg/tree-ssa/ehcleanup-1.C: Update.
+
 2009-04-25  Janus Weil  <janus@gcc.gnu.org>
 
        PR fortran/39688
index f4c81d3..3de72aa 100644 (file)
@@ -1,4 +1,4 @@
-// { dg-options "-O2 -fdump-tree-ehcleanup1" }
+// { dg-options "-O2 -fdump-tree-ehcleanup1-details" }
 extern void can_throw ();
 class a
 {
index d514f45..329932d 100644 (file)
@@ -4800,6 +4800,9 @@ gimple_redirect_edge_and_branch (edge e, basic_block dest)
   if (e->dest == dest)
     return NULL;
 
+  if (e->flags & EDGE_EH)
+    return redirect_eh_edge (e, dest);
+
   gsi = gsi_last_bb (bb);
   stmt = gsi_end_p (gsi) ? NULL : gsi_stmt (gsi);
 
index c9268f9..80014e1 100644 (file)
@@ -1962,7 +1962,7 @@ make_eh_edge (struct eh_region *region, void *data)
   src = gimple_bb (stmt);
   dst = label_to_block (lab);
 
-  make_edge (src, dst, EDGE_ABNORMAL | EDGE_EH);
+  make_edge (src, dst, EDGE_EH);
 }
 
 /* See if STMT is call that might be inlined.  */
@@ -2019,6 +2019,50 @@ make_eh_edges (gimple stmt)
     EDGE_SUCC (bb, 0)->probability = REG_BR_PROB_BASE;
 }
 
+/* Redirect EH edge E to NEW_BB.  */
+
+edge
+redirect_eh_edge (edge e, basic_block new_bb)
+{
+  gimple stmt = gsi_stmt (gsi_last_bb (e->src));
+  int region_nr, new_region_nr;
+  bool is_resx;
+  bool inlinable = false;
+  tree label = gimple_block_label (new_bb);
+  struct eh_region *r;
+
+  if (gimple_code (stmt) == GIMPLE_RESX)
+    {
+      region_nr = gimple_resx_region (stmt);
+      is_resx = true;
+    }
+  else
+    {
+      region_nr = lookup_stmt_eh_region (stmt);
+      gcc_assert (region_nr >= 0);
+      is_resx = false;
+      inlinable = inlinable_call_p (stmt);
+    }
+
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    fprintf (dump_file, "Redirecting EH edge %i->%i to %i, region %i, resx %i\n",
+            e->src->index, e->dest->index, new_bb->index, region_nr, is_resx);
+  r = redirect_eh_edge_to_label (e, label, is_resx, inlinable, region_nr);
+  new_region_nr = get_eh_region_number (r);
+  if (new_region_nr != region_nr)
+    {
+      if (is_resx)
+        gimple_resx_set_region (stmt, new_region_nr);
+      else
+        {
+         remove_stmt_from_eh_region (stmt);
+         add_stmt_to_eh_region (stmt, new_region_nr);
+        }
+    }
+  e = ssa_redirect_edge (e, new_bb);
+  return e;
+}
+
 static bool mark_eh_edge_found_error;
 
 /* Mark edge make_eh_edge would create for given region by setting it aux
@@ -2702,7 +2746,9 @@ tree_remove_unreachable_handlers (void)
              SET_BIT (reachable, region);
          }
        if (gimple_code (stmt) == GIMPLE_RESX)
-         SET_BIT (reachable, gimple_resx_region (stmt));
+         SET_BIT (reachable,
+                  VEC_index (eh_region, cfun->eh->region_array,
+                             gimple_resx_region (stmt))->region_number);
        if ((region = lookup_stmt_eh_region (stmt)) >= 0)
          SET_BIT (contains_stmt, region);
       }
@@ -2937,7 +2983,7 @@ make_eh_edge_and_update_phi (struct eh_region *region, void *data)
     }
   dominance_info_invalidated = true;
   e2 = find_edge (info->bb_to_remove, dst);
-  e = make_edge (src, dst, EDGE_ABNORMAL | EDGE_EH);
+  e = make_edge (src, dst, EDGE_EH);
   e->aux = e;
   gcc_assert (e2);
   for (si = gsi_start_phis (dst); !gsi_end_p (si); gsi_next (&si))
@@ -3091,7 +3137,11 @@ cleanup_empty_eh (basic_block bb, VEC(int,heap) * label_to_region)
         is really dead.  */
 
       if (found && !has_non_eh_preds)
-        remove_eh_region (region);
+        {
+          if (dump_file && (dump_flags & TDF_DETAILS))
+            fprintf (dump_file, "Empty EH handler %i removed.\n", region);
+          remove_eh_region (region);
+       }
       else if (!removed_some)
         return false;
 
index b59774f..8cb69ac 100644 (file)
@@ -32,13 +32,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-reference.h"
 #include "tree-ssa-alias.h"
 
-/* Forward declare structures for the garbage collector GTY markers.  */
-#ifndef GCC_BASIC_BLOCK_H
-struct edge_def;
-typedef struct edge_def *edge;
-struct basic_block_def;
-typedef struct basic_block_def *basic_block;
-#endif
 struct static_var_ann_d;
 
 
@@ -974,5 +967,6 @@ unsigned int execute_fixup_cfg (void);
 void swap_tree_operands (gimple, tree *, tree *);
 
 int least_common_multiple (int, int);
+edge redirect_eh_edge (edge e, basic_block new_bb);
 
 #endif /* _TREE_FLOW_H  */
index 0b02377..57e1d32 100644 (file)
@@ -9320,4 +9320,16 @@ block_ultimate_origin (const_tree block)
     }
 }
 
+/* Return true if T1 and T2 are equivalent lists.  */
+
+bool
+list_equal_p (const_tree t1, const_tree t2)
+{
+  for (; t1 && t2; t1 = TREE_CHAIN (t1) , t2 = TREE_CHAIN (t2))
+    if (TREE_VALUE (t1) != TREE_VALUE (t2))
+      return false;
+  return !t1 && !t2;
+}
+
+
 #include "gt-tree.h"
index ef1b420..4cd9b7d 100644 (file)
@@ -5134,6 +5134,7 @@ struct GTY(()) tree_map_base {
 extern int tree_map_base_eq (const void *, const void *);
 extern unsigned int tree_map_base_hash (const void *);
 extern int tree_map_base_marked_p (const void *);
+extern bool list_equal_p (const_tree, const_tree);
 
 /* Map from a tree to another tree.  */