This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

pretty-ipa merge 16: EH redirection


Hi,
this patch implements EH redirection.  The basic idea is simple involving
duplicating nodes in EH tree.  When we want to redirect edge a->b to c, we look
for region r, we do following steps:
  1) trace is constructed: it is list of regions that might be reached
     from r via foreach_reachable_handler.  This is less than the path
     up from r to the root, since some regions don't have any effect,
     such as catch regions
  2) if there is only one edge to the basic block a, all we need is to
     update all labels in trace from labels contained in b to labels of c
     and exit.
  3) otherwise we look for last region r2 in trace still referring to label of b
  4) we duplicate all regions in trace starting from the r2 to r and when duplicating
     try block, we also duplicate all associated catch blocks
  5) finally we update labels in all duplicated regions from labels in b to label of c.

In combination of edge splitting this produce a lot of redundant regions.  This
still works since RTL code will produce many landing pads getting into given
label, but for sane code size we need reverse transformation that is
implemented in function merge_peers.  Semantically equivalent regions gets that
share label gets unified. So after cfgcleanup done post-PRE the regions are
merged again.

There is important change in a way that now EH region can be reached via region
r and leaved via resx of region r2 when region r was originally created by
duplicating r2.  There is nothing to do about it and no code that really rely
on the fact that EH exceptions are resumed by same region: EH tree is actually
just compactified representaion of action lists that we want to do on each
exception.

I tested the code for a while on C++ testers on pretty-ipa.  There are not any
dramatic code quality improvements, just few improvements in libstdc++ tests.
This is sort of expected: we don't have any benchmarks with EH really in hot
parts of the test. (I mean no taken exceptions, but just try...catch regions).
I am still looking for better benchmark here.

There is no code size growth with exception of -fprofile-generate tramp3d, where we
now actually profile the EH edges, so this is expected too.

For tramp3d we perform now  10028 redirections. 6599 don't need any
duplications, 3423 that do need duplication happens in crited. Most of the rest
happens in copyprop4 that re-merge regions after critical edge splitting.
Out-of-ssa does 7 redirections and it is possible to trim this down too by
adjusting cost of EH edge splitting being bigger in code size than other edges.
I will send this as followup.  PRE and phicprop does both about 90
redirections.

4387 duplicate regions are created, 3797 regions are merged. The disproportion
comes primarily from fact that some EH regions are eliminated as dead first.
Binary size goes from 6666039 to 6675635, and this really is code being moved
down to EH edges from hot path. The situation here is improved on pretty-ipa
where I can DCE filter_expr/obje_ref_expr that allows more merging and code
size actually improves.

It would be possible to trim down the code by not splitting EH edges that would
eliminate pretty much all the expenses, but I would like to do so, since it
allows elimination of partially dead code and other tricks and it keeps
compiler more regular.  I.e. there are just few places we need to care about EH
edges compared to places we need to care about abnormals.  I also plan to
implement logic in out-of-ssa allowing to split abnormal edges by adding
conditionals:  since abnormal edges are now comming basically only from
computed goto (and those are redirectable when computed goto is shared), from
longjmp/setjmp and from nonlocal gotos, I believe we can just get rid of
ABNORMAL_PHI code.

Bootstrapped/regtested x86_64-linux with and without sjlj exceptions, OK?

Honza

	* 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 (edge_def): Forward declaration.
	(redirect_eh_edge_to_label): New.
	* tree-flow.h (redirect_eh_edge): New.
	* Makefile.in (except.o): Add dependency on tree-flow.h
	* tree-cfg.c (gimple_redirect_edge_and_branch): Handle EH edges.
Index: tree-eh.c
===================================================================
*** tree-eh.c	(revision 146763)
--- tree-eh.c	(working copy)
*************** make_eh_edge (struct eh_region *region, 
*** 1962,1968 ****
    src = gimple_bb (stmt);
    dst = label_to_block (lab);
  
!   make_edge (src, dst, EDGE_ABNORMAL | EDGE_EH);
  }
  
  /* See if STMT is call that might be inlined.  */
--- 1962,1968 ----
    src = gimple_bb (stmt);
    dst = label_to_block (lab);
  
!   make_edge (src, dst, EDGE_EH);
  }
  
  /* See if STMT is call that might be inlined.  */
*************** make_eh_edges (gimple stmt)
*** 2019,2024 ****
--- 2019,2068 ----
      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)
+     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
*************** make_eh_edge_and_update_phi (struct eh_r
*** 2937,2943 ****
      }
    dominance_info_invalidated = true;
    e2 = find_edge (info->bb_to_remove, dst);
!   e = make_edge (src, dst, EDGE_ABNORMAL | EDGE_EH);
    e->aux = e;
    gcc_assert (e2);
    for (si = gsi_start_phis (dst); !gsi_end_p (si); gsi_next (&si))
--- 2981,2987 ----
      }
    dominance_info_invalidated = true;
    e2 = find_edge (info->bb_to_remove, dst);
!   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))
Index: except.c
===================================================================
*** except.c	(revision 146763)
--- except.c	(working copy)
*************** along with GCC; see the file COPYING3.  
*** 77,82 ****
--- 77,83 ----
  #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.  */
*************** bring_to_root (struct eh_region *r)
*** 628,633 ****
--- 629,871 ----
    cfun->eh->region_tree = r;
  }
  
+ /* Return true if T1 and T2 are equivalent lists.  */
+ 
+ static bool
+ list_match (tree t1, 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;
+ }
+ 
+ /* 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)
+ {
+   if (r1->type != r2->type)
+     return false;
+   if (r1->tree_label != r2->tree_label)
+     return false;
+   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_match (r1->u.eh_catch.type_list, r2->u.eh_catch.type_list))
+ 	  return false;
+         if (!list_match (r1->u.eh_catch.filter_list,
+ 			 r2->u.eh_catch.filter_list))
+ 	  return false;
+         break;
+       case ERT_ALLOWED_EXCEPTIONS:
+         if (!list_match (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;
+ }
+ 
+ /* Merge region R2 into 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 |= TREE_HASH (TREE_VALUE (t));
+   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;
+ 
+   val <<= 20;
+   if (region->tree_label)
+     val |= LABEL_DECL_UID (region->tree_label);
+   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 |= hash_eh_region (c);
+         }
+ 	break;
+       case ERT_CATCH:
+         val |= hash_type_list (region->u.eh_catch.type_list);
+         break;
+       case ERT_ALLOWED_EXCEPTIONS:
+         val |= hash_type_list (region->u.allowed.type_list);
+         val |= region->u.allowed.filter;
+ 	break;
+       case ERT_THROW:
+         val |= TYPE_UID (region->u.eh_throw.type);
+ 	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 < 1)
+     {
+       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;
+ 		}
+ 	    }
+ 	}
+     }
+   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). */
*************** remove_unreachable_regions (sbitmap reac
*** 641,646 ****
--- 879,887 ----
    struct eh_region *local_must_not_throw = NULL;
    struct eh_region *first_must_not_throw = NULL;
  
+ #ifdef ENABLE_CHECKING
+   verify_eh_tree (cfun);
+ #endif
    for (i = cfun->eh->last_region_number; i > 0; --i)
      {
        r = VEC_index (eh_region, cfun->eh->region_array, i);
*************** remove_unreachable_regions (sbitmap reac
*** 748,753 ****
--- 989,995 ----
        else
  	bring_to_root (r);
      }
+   merge_peers (cfun->eh->region_tree);
  #ifdef ENABLE_CHECKING
    verify_eh_tree (cfun);
  #endif
*************** duplicate_eh_regions (struct function *i
*** 1140,1145 ****
--- 1382,1618 ----
    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.  */
  
*************** build_post_landing_pads (void)
*** 1478,1483 ****
--- 1951,1963 ----
        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
*************** build_post_landing_pads (void)
*** 1537,1542 ****
--- 2017,2025 ----
  	  break;
  
  	case ERT_ALLOWED_EXCEPTIONS:
+ 
+ 	  if (!region->label)
+ 	    break;
  	  region->post_landing_pad = gen_label_rtx ();
  
  	  start_sequence ();
*************** dw2_build_landing_pads (void)
*** 1679,1684 ****
--- 2162,2170 ----
  	  && region->type != ERT_ALLOWED_EXCEPTIONS)
  	continue;
  
+       if (!region->post_landing_pad)
+ 	continue;
+ 
        start_sequence ();
  
        region->landing_pad = gen_label_rtx ();
Index: except.h
===================================================================
*** except.h	(revision 146763)
--- except.h	(working copy)
*************** struct GTY(()) throw_stmt_node {
*** 272,281 ****
--- 273,284 ----
    gimple stmt;
    int region_nr;
  };
+ struct edge_def;
  
  extern struct htab *get_eh_throw_stmt_table (struct function *);
  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: tree-flow.h
===================================================================
*** tree-flow.h	(revision 146763)
--- tree-flow.h	(working copy)
*************** unsigned int execute_fixup_cfg (void);
*** 974,978 ****
--- 974,979 ----
  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: Makefile.in
===================================================================
*** Makefile.in	(revision 146763)
--- Makefile.in	(working copy)
*************** except.o : except.c $(CONFIG_H) $(SYSTEM
*** 2525,2531 ****
     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)
  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 \
--- 2525,2531 ----
     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) $(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: tree-cfg.c
===================================================================
*** tree-cfg.c	(revision 146763)
--- tree-cfg.c	(working copy)
*************** gimple_redirect_edge_and_branch (edge e,
*** 4800,4805 ****
--- 4800,4808 ----
    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 Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]