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] More flexibility to tree EH code


Hi,
EH redirection breaks two assumption tree EH code takes:
  1) multiple EH handlers can share same label.  This is not difficult to handle
     because we just need to keep list of handlers sharing label.
  2) local EH handler can resume to different EH handler that is outer handler.
     This is inavoidable when redirecting and it is not real problem anywhere,
     just we need to be cureful in code like ehcleanup to properly update EH
     tree to reflect what is going on.

Bootstrapped/regtested x86_64-linux, comitted to pretty-ipa.

	* tree-eh.c (tree_remove_unreachable_handlers): Handle shared labels.
	(tree_empty_eh_handler_p): Verify that there are no non-EH predecestors
	(cleanup_empty_eh): Get label to region map; handle regions sharing
	same label.
	(cleanup_eh): Compute label to region map.
	* except.c (struct eh_region): New field next_region_sharing_label.
	(label_to_region_map): Compute shared label lists.
	(get_next_region_sharing_label): New function.
	(rtl_remove_unreachable_regions): Handle shared labels.
	(remove_eh_region_and_replace): New function.
	* except.h (remove_eh_region_and_replace,
	get_next_region_sharing_label): Declare.


Index: tree-eh.c
===================================================================
*** tree-eh.c	(revision 145555)
--- tree-eh.c	(working copy)
*************** tree_remove_unreachable_handlers (void)
*** 2695,2702 ****
  	if (gimple_code (stmt) == GIMPLE_LABEL && has_eh_preds)
  	  {
  	    int uid = LABEL_DECL_UID (gimple_label_label (stmt));
! 	    int region = VEC_index (int, label_to_region, uid);
! 	    SET_BIT (reachable, region);
  	  }
  	if (gimple_code (stmt) == GIMPLE_RESX)
  	  SET_BIT (reachable, gimple_resx_region (stmt));
--- 2695,2705 ----
  	if (gimple_code (stmt) == GIMPLE_LABEL && has_eh_preds)
  	  {
  	    int uid = LABEL_DECL_UID (gimple_label_label (stmt));
! 	    int region;
! 
! 	    for (region = VEC_index (int, label_to_region, uid);
! 		 region; region = get_next_region_sharing_label (region))
! 	      SET_BIT (reachable, region);
  	  }
  	if (gimple_code (stmt) == GIMPLE_RESX)
  	  SET_BIT (reachable, gimple_resx_region (stmt));
*************** tree_empty_eh_handler_p (basic_block bb)
*** 2743,2748 ****
--- 2746,2753 ----
  {
    gimple_stmt_iterator gsi;
    int region;
+   edge_iterator ei;
+   edge e;
    use_operand_p imm_use;
    gimple use_stmt;
  
*************** tree_empty_eh_handler_p (basic_block bb)
*** 2815,2820 ****
--- 2820,2836 ----
        if (gsi_end_p (gsi))
  	return 0;
      }
+ 
+   /* Splitting critical edges might create handler with non-EH predecestors.
+      Do not care about it: if we end up putting nothing on those critical
+      edges, the handlers will be merged again.  If not, we will end up with
+      extra EH landing pad doing nothing.  Not terribly bad given the fact
+      that outer block of that EH landing pad is anyway reachable from
+      the split critical edge with non-trivial cleanup.  */
+   FOR_EACH_EDGE (e, ei, bb->preds)
+     if (!(e->flags & EDGE_EH))
+       return 0;
+ 
    while (gimple_code (gsi_stmt (gsi)) == GIMPLE_LABEL)
      {
        if (gimple_label_label (gsi_stmt (gsi))
*************** update_eh_edges (gimple stmt, basic_bloc
*** 3017,3023 ****
     This is similar to jump forwarding, just across EH edges.  */
  
  static bool
! cleanup_empty_eh (basic_block bb)
  {
    int region;
    gimple_stmt_iterator si;
--- 3033,3039 ----
     This is similar to jump forwarding, just across EH edges.  */
  
  static bool
! cleanup_empty_eh (basic_block bb, VEC(int,heap) * label_to_region)
  {
    int region;
    gimple_stmt_iterator si;
*************** cleanup_empty_eh (basic_block bb)
*** 3030,3036 ****
--- 3046,3079 ----
        && all_phis_safe_to_merge (bb))
      {
        edge e;
+       bool found = false;
+       gimple_stmt_iterator gsi;
  
+       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+         if (gimple_code (gsi_stmt (gsi)) == GIMPLE_LABEL)
+ 	  {
+ 	    int uid = LABEL_DECL_UID (gimple_label_label (gsi_stmt (gsi)));
+ 	    int r = VEC_index (int, label_to_region, uid);
+ 	    int next;
+ 
+ 	    while (r)
+ 	      {
+ 		next = get_next_region_sharing_label (r);
+ 		if (r == region)
+ 		  found = true;
+ 		else
+ 		  {
+ 		     remove_eh_region_and_replace (r, region);
+ 		     if (dump_file)
+ 		       fprintf (dump_file, "Empty EH handler %i removed and "
+ 		       		"replaced by %i\n", r, region);
+ 		  }
+ 		r = next;
+ 	      }
+ 	  }
+ 	else
+ 	  break;
+       gcc_assert (found);
        remove_eh_region (region);
  
        while ((e = ei_safe_edge (ei_start (bb->preds))))
*************** cleanup_empty_eh (basic_block bb)
*** 3041,3048 ****
  	    update_eh_edges (last_stmt (src), bb, e);
  	  remove_edge (e);
  	}
-       if (dump_file)
- 	fprintf (dump_file, "Empty EH handler %i removed\n", region);
  
        /* Verify that we eliminated all uses of PHI we are going to remove.
           If we didn't, rebuild SSA on affected variable (this is allowed only
--- 3084,3089 ----
*************** cleanup_eh (void)
*** 3111,3116 ****
--- 3152,3158 ----
  {
    bool changed = false;
    basic_block bb;
+   VEC(int,heap) * label_to_region;
    int i;
  
    if (!cfun->eh)
*************** cleanup_eh (void)
*** 3121,3134 ****
        dump_eh_tree (dump_file, cfun);
      }
  
    dominance_info_invalidated = false;
    /* We cannot use FOR_EACH_BB, since the basic blocks may get removed.  */
    for (i = NUM_FIXED_BLOCKS; i < last_basic_block; i++)
      {
        bb = BASIC_BLOCK (i);
        if (bb)
! 	changed |= cleanup_empty_eh (bb);
      }
    if (dominance_info_invalidated)
      {
        free_dominance_info (CDI_DOMINATORS);
--- 3163,3178 ----
        dump_eh_tree (dump_file, cfun);
      }
  
+   label_to_region = label_to_region_map ();
    dominance_info_invalidated = false;
    /* We cannot use FOR_EACH_BB, since the basic blocks may get removed.  */
    for (i = NUM_FIXED_BLOCKS; i < last_basic_block; i++)
      {
        bb = BASIC_BLOCK (i);
        if (bb)
! 	changed |= cleanup_empty_eh (bb, label_to_region);
      }
+   VEC_free (int, heap, label_to_region);
    if (dominance_info_invalidated)
      {
        free_dominance_info (CDI_DOMINATORS);
Index: except.c
===================================================================
*** except.c	(revision 145555)
--- except.c	(working copy)
*************** struct eh_region GTY(())
*** 124,129 ****
--- 124,131 ----
    struct eh_region *inner;
    struct eh_region *next_peer;
  
+   struct eh_region *next_region_sharing_label;
+ 
    /* An identifier for this region.  */
    int region_number;
  
*************** remove_unreachable_regions (sbitmap reac
*** 866,876 ****
  /* Return array mapping LABEL_DECL_UID to region such that region's tree_label
     is identical to label.  */
  
! VEC(int,heap) *
  label_to_region_map (void)
  {
!   VEC(int,heap) * label_to_region = NULL;
    int i;
  
    VEC_safe_grow_cleared (int, heap, label_to_region,
  			 cfun->cfg->last_label_uid + 1);
--- 868,879 ----
  /* Return array mapping LABEL_DECL_UID to region such that region's tree_label
     is identical to label.  */
  
! VEC (int, heap) *
  label_to_region_map (void)
  {
!   VEC (int, heap) * label_to_region = NULL;
    int i;
+   int idx;
  
    VEC_safe_grow_cleared (int, heap, label_to_region,
  			 cfun->cfg->last_label_uid + 1);
*************** label_to_region_map (void)
*** 878,885 ****
      {
        struct eh_region *r = VEC_index (eh_region, cfun->eh->region_array, i);
        if (r && r->region_number == i
!       	  && r->tree_label && LABEL_DECL_UID (r->tree_label) >= 0)
  	{
  	  VEC_replace (int, label_to_region, LABEL_DECL_UID (r->tree_label),
  		       i);
  	}
--- 881,894 ----
      {
        struct eh_region *r = VEC_index (eh_region, cfun->eh->region_array, i);
        if (r && r->region_number == i
! 	  && r->tree_label && LABEL_DECL_UID (r->tree_label) >= 0)
  	{
+ 	  if ((idx = VEC_index (int, label_to_region,
+ 				LABEL_DECL_UID (r->tree_label))) != 0)
+ 	      r->next_region_sharing_label =
+ 	      VEC_index (eh_region, cfun->eh->region_array, idx);
+ 	  else
+ 	    r->next_region_sharing_label = NULL;
  	  VEC_replace (int, label_to_region, LABEL_DECL_UID (r->tree_label),
  		       i);
  	}
*************** num_eh_regions (void)
*** 894,899 ****
--- 903,920 ----
    return cfun->eh->last_region_number + 1;
  }
  
+ int
+ get_next_region_sharing_label (int region)
+ {
+   struct eh_region *r;
+   if (!region)
+     return 0;
+   r = VEC_index (eh_region, cfun->eh->region_array, region);
+   if (!r || !r->next_region_sharing_label)
+     return 0;
+   return r->next_region_sharing_label->region_number;
+ }
+ 
  /* Remove all regions whose labels are not reachable from insns.  */
  
  static void
*************** rtl_remove_unreachable_regions (rtx insn
*** 910,918 ****
--- 931,941 ----
  
    for (i = cfun->eh->last_region_number; i > 0; --i)
      {
+       int id;
        r = VEC_index (eh_region, cfun->eh->region_array, i);
        if (!r || r->region_number != i)
  	continue;
+       r->next_region_sharing_label = NULL;
  
        if (r->resume)
  	{
*************** rtl_remove_unreachable_regions (rtx insn
*** 921,933 ****
  	}
        if (r->label)
  	{
! 	  gcc_assert (!uid_region_num[INSN_UID (r->label)]);
  	  uid_region_num[INSN_UID (r->label)] = i;
  	}
      }
  
    for (insn = insns; insn; insn = NEXT_INSN (insn))
!     SET_BIT (reachable, uid_region_num[INSN_UID (insn)]);
  
    remove_unreachable_regions (reachable, NULL);
  
--- 944,975 ----
  	}
        if (r->label)
  	{
! 	  id = uid_region_num[INSN_UID (r->label)];
! 	  if (id != 0)
! 	     r->next_region_sharing_label = VEC_index (eh_region,
! 						       cfun->eh->region_array,
! 						       id);
  	  uid_region_num[INSN_UID (r->label)] = i;
  	}
      }
  
    for (insn = insns; insn; insn = NEXT_INSN (insn))
!     {
!       int region;
!       SET_BIT (reachable, uid_region_num[INSN_UID (insn)]);
!       if (GET_CODE (insn) == CODE_LABEL)
! 	{
! 	  region = get_next_region_sharing_label (uid_region_num[INSN_UID (insn)]);
! 	  while (region)
! 	    {
! 	      SET_BIT (reachable, region);
! 	      region = get_next_region_sharing_label (region);
! 	    }
! 	}
!       if (GET_CODE (insn) == JUMP_INSN
! 	  && GET_CODE (PATTERN (insn)) == RESX)
!         SET_BIT (reachable, XINT (PATTERN (insn), 0));
!     }
  
    remove_unreachable_regions (reachable, NULL);
  
*************** remove_eh_region (int r)
*** 2617,2622 ****
--- 2659,2677 ----
    remove_eh_handler (region);
  }
  
+ /* Remove Eh region R that has turned out to have no code in its handler
+    and replace in by R2.  */
+ 
+ void
+ remove_eh_region_and_replace (int r, int r2)
+ {
+   struct eh_region *region, *region2;
+ 
+   region = VEC_index (eh_region, cfun->eh->region_array, r);
+   region2 = VEC_index (eh_region, cfun->eh->region_array, r2);
+   remove_eh_handler_and_replace (region, region2);
+ }
+ 
  /* Invokes CALLBACK for every exception handler label.  Only used by old
     loop hackery; should not be used by new code.  */
  
Index: except.h
===================================================================
*** except.h	(revision 145555)
--- except.h	(working copy)
*************** extern void init_eh_for_function (void);
*** 64,69 ****
--- 64,70 ----
  extern rtx reachable_handlers (rtx);
  extern void maybe_remove_eh_handler (rtx);
  void remove_eh_region (int);
+ void remove_eh_region_and_replace (int, int);
  
  extern void convert_from_eh_region_ranges (void);
  extern unsigned int convert_to_eh_region_ranges (void);
*************** extern void remove_unreachable_regions (
*** 182,184 ****
--- 183,186 ----
  extern VEC(int,heap) * label_to_region_map (void);
  extern int num_eh_regions (void);
  extern bitmap must_not_throw_labels (void);
+ extern int get_next_region_sharing_label (int);


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]