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]

EH flow patch


I've checked the following patch in. This was approved by Jim
wilson and bootstraps on Solaris.  This is required to build libstdtc++ 
with -fnew-exceptions.

Basically, this patch makes flow and the EH regions play together a lot better.

Flow wasn't treating REG_EH_RETHROW's correctly, and it turns out there
were also a few latent bugs with the rethrow code too.  Anyway, This
patch changes a number of things:
  REG_EH_RETHROW now has a symbol_ref of the rethrow symbol instead of a
region number. This allows rethrows to be inlined properly.
  A set of routines to figure out the region nesting order and determine
exactly which handlers can be reached from any given insn now exist. A side
effect of this is that now when we build the flow graph, we only make
edges to the actual handlers which can be reached, instead of all of them.
If the current region has a catch_all clause, we don't have edges to any
of the outer handlers. This is only effective with -fnew-exceptions.
  rethrow regions are better tracked. We were way to pessimistic before,
and a lot of uneccessary regions were in the region table than where
needed to be. Now just whats needed is there. (-fnew-exceptions only)
  We  no longer overload the value of SYMBOL_REF_USED for rethrow symbols.
There's a flag in the structure now.
  There were a few places where we were  not observing the REG_EH_REGION note
properly, so I fixed those.

  This patch should solve a lot of EH and optimization problems. Its also
sets things up well in preparation for more extensive use of
the REG_EH_REGION note in functions which don't throw.

Next we should attach that note to all the EH runtime routines
which get called (ie __cp_push_exception, etc) then we should see some
dramatic decreases in the exception table size. (again, -fnew-exceptions only)

Andrew


	* except.h (eh_nesting_info): Add new structure defintion.
	(init_eh_nesting_info, free_eh_nesting_info): Add function prototypes.
	(reachable_handlers, update_rethrow_references): Add function 
	prototypes.
	* rtl.h (struct rtvec_def): Update comments.  REG_EH_RETHROW takes
	a rethrow symbol instead of an integer exception region number.
	* flow.c (Make_edges): Use new exception nesting routines to determine 
	which handlers are reachable from a CALL or asynchronous insn.
	Dont add an edge for calls with a REG_EH_REGION of -1 to non-local
	goto receivers.
	(delete_eh_regions): Update rethrow labels, and don't delete 
	regions which are the target of a rethrow.
	* except.c (struct func_eh_entry): Add rethrow_ref field, now we can
	avoid overloading the SYMBOL_REF_USED flag.
	(rethrow_symbol_map): Use new rethrow_ref field.
	(rethrow_used): Use new rethrow_ref field.
	(expand_rethrow): REG_EH_RETHROW now has a SYMBOL_REF instead 
	of an integer.  Fix formatting.
	(output_exception_table_entry): Use new rethrow_ref field.
	(can_throw): Check for EH_REGION_NOTE before deciding
	whether a CALL can throw or not.
	(scan_region): Call rethrow_used() instead of accessing data structure.
	(update_rethrow_references): New function to make sure only regions
	which are still targets of a rethrow are flagged as such.
	(process_nestinfo): New static function to initialize a handler 
	list for a specific region.
	(init_eh_nesting_info): New function to allocate and initialize
	the list of all EH handlers reachable from all regions.
	(reachable_handlers): New function to retrieve the list of handlers
	reachable from a specific region and insn.
	(free_eh_nesting_info): New function to dispose of a list of
	reachable handlers.


Index: gcc/except.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/except.h,v
retrieving revision 1.28
diff -c -p -r1.28 except.h
*** except.h	1999/01/06 20:44:22	1.28
--- except.h	1999/06/22 13:19:59
*************** rtx rethrow_symbol_map                  
*** 213,218 ****
--- 213,223 ----
  
  int rethrow_used                                PROTO((int));
  
+ /* Update the rethrow references to reflect rethrows which have been
+    optimized away.  */
+ 
+ void update_rethrow_references			PROTO((void));
+ 
  /* Return the region number a this is the rethrow label for. */
  
  int eh_region_from_symbol                       PROTO((rtx));
*************** struct handler_info *get_first_handler  
*** 224,229 ****
--- 229,274 ----
  /* Find all the runtime handlers type matches currently referenced */
  
  int find_all_handler_type_matches               PROTO((void ***));
+ 
+ /* The eh_nesting_info structure is used to find a list of valid handlers
+    for any arbitrary exception region.  When init_eh_nesting_info is called,
+    the information is all pre-calculated and entered in this structure.
+    REGION_INDEX is a vector over all possible region numbers.  Since the
+    number of regions is typically much smaller than the range of block
+    numbers, this is a sparse vector and the other data structures are 
+    represented as dense vectors.  Indexed with an exception region number, this
+    returns the index to use in the other data structures to retreive the
+    correct information.
+    HANDLERS is an array of vectors which point to handler_info structures.
+    when indexed, it gives the list of all possible handlers which can 
+    be reached by a throw from this exception region.
+    NUM_HANDLERS is the equivilent array indicating how many handler
+    pointers there are in the HANDLERS vector.
+    OUTER_INDEX indicates which index represents the information for the
+    outer block.  0 indicates there is no outer context.
+    REGION_COUNT is the number of regions.  */
+ 
+ typedef struct eh_nesting 
+ {
+   int *region_index;
+   handler_info ***handlers;
+   int *num_handlers;
+   int *outer_index;
+   int region_count;
+ } eh_nesting_info;
+ 
+ /* Initialize the eh_nesting_info structure.  */
+ 
+ eh_nesting_info *init_eh_nesting_info 		PROTO((void));
+ 
+ /* Get a list of handlers reachable from a an exception region/insn.  */
+ 
+ int reachable_handlers 			PROTO((int, eh_nesting_info *, rtx, 
+ 					       handler_info ***handlers));
+ 
+ /* Free the eh_nesting_info structure.  */
+ 
+ void free_eh_nesting_info 			PROTO((eh_nesting_info *));
  
  extern void init_eh				PROTO((void));
  
Index: gcc/rtl.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/rtl.h,v
retrieving revision 1.105
diff -c -p -r1.105 rtl.h
*** rtl.h	1999/04/27 17:08:34	1.105
--- rtl.h	1999/06/22 13:20:01
*************** typedef struct rtvec_def{
*** 344,356 ****
     rtx is used instead of intuition.  */
  /*   REG_EH_REGION is used to indicate what exception region an INSN
     belongs in.  This can be used to indicate what region a call may throw
!    to.  A REGION of 0 indicates that a call cannot throw at all.
!    A REGION  of -1 indicates that it cannot throw, nor will it execute
     a non-local goto.
!      REG_EH_RETHROW is used to indicate what that a call is actually a
!    call to rethrow, and specifies which region the rethrow is targetting.
!    This provides a way to generate the non standard flow edges required 
!    for a rethrow.  */
     
  
  #define REG_NOTES(INSN)	((INSN)->fld[6].rtx)
--- 344,356 ----
     rtx is used instead of intuition.  */
  /*   REG_EH_REGION is used to indicate what exception region an INSN
     belongs in.  This can be used to indicate what region a call may throw
!    to. a REGION of 0 indicates that a call cannot throw at all.
!    a REGION  of -1 indicates that it cannot throw, nor will it execute
     a non-local goto.
!      REG_EH_RETHROW is used to indicate that a call is actually a
!    call to rethrow, and specifies the rethrow symbol for the region 
!    the rethrow is targetting.  This provides a way to generate the 
!    non standard flow edges required for a rethrow. */
     
  
  #define REG_NOTES(INSN)	((INSN)->fld[6].rtx)
Index: gcc/flow.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/flow.c,v
retrieving revision 1.123
diff -c -p -r1.123 flow.c
*** flow.c	1999/05/26 08:50:01	1.123
--- flow.c	1999/06/22 13:20:06
*************** make_edges (label_value_list, bb_eh_end)
*** 869,874 ****
--- 869,875 ----
       rtx *bb_eh_end;
  {
    int i;
+   eh_nesting_info *eh_nest_info = init_eh_nesting_info ();
  
    /* Assume no computed jump; revise as we create edges.  */
    current_function_has_computed_jump = 0;
*************** make_edges (label_value_list, bb_eh_end)
*** 978,1018 ****
        if (code == CALL_INSN || asynchronous_exceptions)
  	{
  	  int is_call = (code == CALL_INSN ? EDGE_ABNORMAL_CALL : 0);
! 	  handler_info *ptr;
! 
! 	  /* Use REG_EH_RETHROW and REG_EH_REGION if available.  */
! 	  /* ??? REG_EH_REGION is not generated presently.  Is it
! 	     inteded that there be multiple notes for the regions?
! 	     or is my eh_list collection redundant with handler linking?  */
! 
! 	  x = find_reg_note (insn, REG_EH_RETHROW, 0);
! 	  if (!x)
! 	    x = find_reg_note (insn, REG_EH_REGION, 0);
! 	  if (x)
! 	    {
! 	      if (XINT (XEXP (x, 0), 0) > 0)
! 		{
! 		  ptr = get_first_handler (XINT (XEXP (x, 0), 0));
! 		  while (ptr)
! 		    {
! 		      make_label_edge (bb, ptr->handler_label,
! 				       EDGE_ABNORMAL | EDGE_EH | is_call);
! 		      ptr = ptr->next;
! 		    }
! 		}
! 	    }
! 	  else
  	    {
! 	      for (x = eh_list; x; x = XEXP (x, 1))
! 		{
! 		  ptr = get_first_handler (NOTE_BLOCK_NUMBER (XEXP (x, 0)));
! 		  while (ptr)
! 		    {
! 		      make_label_edge (bb, ptr->handler_label,
! 				       EDGE_ABNORMAL | EDGE_EH | is_call);
! 		      ptr = ptr->next;
! 		    }
! 		}
  	    }
  
  	  if (code == CALL_INSN && nonlocal_goto_handler_labels)
--- 979,997 ----
        if (code == CALL_INSN || asynchronous_exceptions)
  	{
  	  int is_call = (code == CALL_INSN ? EDGE_ABNORMAL_CALL : 0);
! 	  handler_info **handler_list;
! 	  int eh_region = -1;
! 	  int num;
! 
! 	  if (eh_list)
! 	    eh_region = NOTE_BLOCK_NUMBER (XEXP (eh_list, 0));
! 
! 	  num = reachable_handlers (eh_region, eh_nest_info,
! 				    insn, &handler_list);
! 	  for ( ; num > 0; num--)
  	    {
! 	      make_label_edge (bb, handler_list[num - 1]->handler_label,
! 			       EDGE_ABNORMAL | EDGE_EH | is_call);
  	    }
  
  	  if (code == CALL_INSN && nonlocal_goto_handler_labels)
*************** make_edges (label_value_list, bb_eh_end)
*** 1024,1033 ****
  		 gotos do not have their addresses taken, then only calls to
  		 those functions or to other nested functions that use them
  		 could possibly do nonlocal gotos.  */
! 
! 	      for (x = nonlocal_goto_handler_labels; x ; x = XEXP (x, 1))
! 	        make_label_edge (bb, XEXP (x, 0),
! 			         EDGE_ABNORMAL | EDGE_ABNORMAL_CALL);
  	    }
  	}
  
--- 1003,1015 ----
  		 gotos do not have their addresses taken, then only calls to
  		 those functions or to other nested functions that use them
  		 could possibly do nonlocal gotos.  */
! 	      /* We do know that a REG_EH_REGION note with a value less
! 		 than 0 is guaranteed not to perform a non-local goto.  */
! 	      rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
! 	      if (!note || XINT (XEXP (note, 0), 0) >=  0)
! 		for (x = nonlocal_goto_handler_labels; x ; x = XEXP (x, 1))
! 		  make_label_edge (bb, XEXP (x, 0),
! 				   EDGE_ABNORMAL | EDGE_ABNORMAL_CALL);
  	    }
  	}
  
*************** make_edges (label_value_list, bb_eh_end)
*** 1052,1057 ****
--- 1034,1040 ----
  	    make_edge (bb, BASIC_BLOCK (i + 1), EDGE_FALLTHRU);
  	}
      }
+   free_eh_nesting_info (eh_nest_info);
  }
  
  /* Create an edge between two basic blocks.  FLAGS are auxiliary information
*************** delete_eh_regions ()
*** 1600,1605 ****
--- 1583,1590 ----
  {
    rtx insn;
  
+   update_rethrow_references ();
+ 
    for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
      if (GET_CODE (insn) == NOTE)
        {
*************** delete_eh_regions ()
*** 1607,1614 ****
  	    (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END)) 
  	  {
  	    int num = CODE_LABEL_NUMBER (insn);
! 	    /* A NULL handler indicates a region is no longer needed */
! 	    if (get_first_handler (num) == NULL)
  	      {
  		NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
  		NOTE_SOURCE_FILE (insn) = 0;
--- 1592,1600 ----
  	    (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END)) 
  	  {
  	    int num = CODE_LABEL_NUMBER (insn);
! 	    /* A NULL handler indicates a region is no longer needed,
! 	       as long as it isn't the target of a rethrow.  */
! 	    if (get_first_handler (num) == NULL && ! rethrow_used (num))
  	      {
  		NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
  		NOTE_SOURCE_FILE (insn) = 0;
Index: gcc/except.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/except.c,v
retrieving revision 1.82
diff -c -p -r1.82 except.c
*** except.c	1999/04/15 19:54:09	1.82
--- except.c	1999/06/22 13:20:10
*************** receive_exception_label (handler_label)
*** 740,747 ****
  
  struct func_eh_entry 
  {
!   int range_number;   /* EH region number from EH NOTE insn's */
!   rtx rethrow_label;  /* Label for rethrow */
    struct handler_info *handlers;
  };
  
--- 740,748 ----
  
  struct func_eh_entry 
  {
!   int range_number;   /* EH region number from EH NOTE insn's.  */
!   rtx rethrow_label;  /* Label for rethrow.  */
!   int rethrow_ref;    /* Is rethrow referenced?  */
    struct handler_info *handlers;
  };
  
*************** rethrow_symbol_map (sym, map)
*** 1044,1050 ****
            {
              x = duplicate_eh_handlers (CODE_LABEL_NUMBER (l1), y, map);
              /* Since we're mapping it, it must be used. */
!             SYMBOL_REF_USED (function_eh_regions[x].rethrow_label) = 1;
            }
          return function_eh_regions[x].rethrow_label;
        }
--- 1045,1051 ----
            {
              x = duplicate_eh_handlers (CODE_LABEL_NUMBER (l1), y, map);
              /* Since we're mapping it, it must be used. */
!             function_eh_regions[x].rethrow_ref = 1;
            }
          return function_eh_regions[x].rethrow_label;
        }
*************** rethrow_used (region)
*** 1057,1064 ****
  {
    if (flag_new_exceptions)
      {
!       rtx lab = function_eh_regions[find_func_region (region)].rethrow_label;
!       return (SYMBOL_REF_USED (lab));
      }
    return 0;
  }
--- 1058,1065 ----
  {
    if (flag_new_exceptions)
      {
!       int ret = function_eh_regions[find_func_region (region)].rethrow_ref;
!       return ret;
      }
    return 0;
  }
*************** expand_rethrow (label)
*** 1965,1987 ****
    else
      if (flag_new_exceptions)
        {
!         rtx insn, val;
!         if (label == NULL_RTX)
!           label = last_rethrow_symbol;
!         emit_library_call (rethrow_libfunc, 0, VOIDmode, 1, label, Pmode);
!         SYMBOL_REF_USED (label) = 1;
  
  	/* Search backwards for the actual call insn.  */
!         insn = get_last_insn ();
  	while (GET_CODE (insn) != CALL_INSN)
  	  insn = PREV_INSN (insn);
  	delete_insns_since (insn);
! 	
!         /* Mark the label/symbol on the call. */
!         val = GEN_INT (eh_region_from_symbol (label));
!         REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EH_RETHROW, val,
  					      REG_NOTES (insn));
!         emit_barrier ();
        }
      else
        emit_jump (label);
--- 1966,1989 ----
    else
      if (flag_new_exceptions)
        {
! 	rtx insn, val;
! 	int region;
! 	if (label == NULL_RTX)
! 	  label = last_rethrow_symbol;
! 	emit_library_call (rethrow_libfunc, 0, VOIDmode, 1, label, Pmode);
! 	region = find_func_region (eh_region_from_symbol (label));
! 	function_eh_regions[region].rethrow_ref = 1;
  
  	/* Search backwards for the actual call insn.  */
! 	insn = get_last_insn ();
  	while (GET_CODE (insn) != CALL_INSN)
  	  insn = PREV_INSN (insn);
  	delete_insns_since (insn);
! 
! 	/* Mark the label/symbol on the call. */
! 	REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EH_RETHROW, label,
  					      REG_NOTES (insn));
! 	emit_barrier ();
        }
      else
        emit_jump (label);
*************** output_exception_table_entry (file, n)
*** 2127,2133 ****
    if (rethrow != NULL_RTX && !flag_new_exceptions)
        rethrow = NULL_RTX;
    if (rethrow != NULL_RTX && handler == NULL)
!     if (! SYMBOL_REF_USED (rethrow))
        rethrow = NULL_RTX;
  
  
--- 2129,2135 ----
    if (rethrow != NULL_RTX && !flag_new_exceptions)
        rethrow = NULL_RTX;
    if (rethrow != NULL_RTX && handler == NULL)
!     if (! function_eh_regions[index].rethrow_ref)
        rethrow = NULL_RTX;
  
  
*************** static int
*** 2481,2489 ****
  can_throw (insn)
       rtx insn;
  {
!   /* Calls can always potentially throw exceptions.  */
    if (GET_CODE (insn) == CALL_INSN)
!     return 1;
  
    if (asynchronous_exceptions)
      {
--- 2483,2496 ----
  can_throw (insn)
       rtx insn;
  {
!   /* Calls can always potentially throw exceptions, unless they have
!      a REG_EH_REGION note with a value of 0 or less.  */
    if (GET_CODE (insn) == CALL_INSN)
!     {
!       rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
!       if (!note || XINT (XEXP (note, 0), 0) > 0)
! 	return 1;
!     }
  
    if (asynchronous_exceptions)
      {
*************** scan_region (insn, n, delete_outer)
*** 2524,2532 ****
    /* Assume we can delete the region.  */
    int delete = 1;
  
-   int r = find_func_region (n);
    /* Can't delete something which is rethrown to. */
!   if (SYMBOL_REF_USED((function_eh_regions[r].rethrow_label)))
      delete = 0;
  
    if (insn == NULL_RTX
--- 2531,2538 ----
    /* Assume we can delete the region.  */
    int delete = 1;
  
    /* Can't delete something which is rethrown to. */
!   if (rethrow_used (n))
      delete = 0;
  
    if (insn == NULL_RTX
*************** exception_optimize ()
*** 2641,2646 ****
--- 2647,2699 ----
  	}
      }
  }
+ 
+ /* This function determines whether any of the exception regions in the
+    current function are targets of a rethrow or not, and set the 
+    reference flag according.  */
+ void
+ update_rethrow_references ()
+ {
+   rtx insn;
+   int x, region;
+   int *saw_region, *saw_rethrow;
+ 
+   if (!flag_new_exceptions)
+     return;
+ 
+   saw_region = (int *) alloca (current_func_eh_entry * sizeof (int));
+   saw_rethrow = (int *) alloca (current_func_eh_entry * sizeof (int));
+   bzero ((char *) saw_region, (current_func_eh_entry * sizeof (int)));
+   bzero ((char *) saw_rethrow, (current_func_eh_entry * sizeof (int)));
+ 
+   /* Determine what regions exist, and whether there are any rethrows
+      to those regions or not.  */
+   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+     if (GET_CODE (insn) == CALL_INSN)
+       {
+ 	rtx note = find_reg_note (insn, REG_EH_RETHROW, NULL_RTX);
+ 	if (note)
+ 	  {
+             region = eh_region_from_symbol (XEXP (note, 0));
+ 	    region = find_func_region  (region);
+ 	    saw_rethrow[region] = 1;
+ 	  }
+       }
+     else
+       if (GET_CODE (insn) == NOTE)
+         {
+ 	  if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
+ 	    {
+ 	      region = find_func_region (NOTE_BLOCK_NUMBER (insn));
+ 	      saw_region[region] = 1;
+ 	    }
+ 	}
+ 
+   /* For any regions we did see, set the referenced flag.  */
+   for (x = 0; x < current_func_eh_entry; x++)
+     if (saw_region[x])
+       function_eh_regions[x].rethrow_ref = saw_rethrow[x];
+ }
  
  /* Various hooks for the DWARF 2 __throw routine.  */
  
*************** in_same_eh_region (insn1, insn2) 
*** 2959,2962 ****
--- 3012,3260 ----
    ret = (insn_eh_region[uid1] == insn_eh_region[uid2]);
    return ret;
  }
+ 
+ 
+ /* This function will initialize the handler list for a specified block.
+    It may recursively call itself if the outer block hasn't been processed
+    yet.  At some point in the future we can trim out handlers which we
+    know cannot be called. (ie, if a block has an INT type handler,
+    control will never be passed to an outer INT type handler).  */
+ static void 
+ process_nestinfo (block, info, nested_eh_region)
+      int block;
+      eh_nesting_info *info;
+      int *nested_eh_region;
+ {
+   handler_info *ptr, *last_ptr = NULL;
+   int x, y, count = 0;
+   int extra = 0;
+   handler_info **extra_handlers;
+   int index = info->region_index[block];
+ 
+   /* If we've already processed this block, simply return. */
+   if (info->num_handlers[index] > 0)
+     return;
+ 
+   for (ptr = get_first_handler (block); ptr; last_ptr = ptr, ptr = ptr->next)
+     count++;
+ 
+  /* pick up any information from the next outer region.  It will already
+     contain a summary of itself and all outer regions to it.  */
+ 
+   if (nested_eh_region [block] != 0) 
+     {
+       int nested_index = info->region_index[nested_eh_region[block]];
+       process_nestinfo (nested_eh_region[block], info, nested_eh_region);
+       extra = info->num_handlers[nested_index];
+       extra_handlers = info->handlers[nested_index];
+       info->outer_index[index] = nested_index;
+     }
  
+   /* If the last handler is either a CATCH_ALL or a cleanup, then we
+      won't use the outer ones since we know control will not go past the
+      catch-all or cleanup.  */
+ 
+   if (last_ptr != NULL && (last_ptr->type_info == NULL 
+   			   || last_ptr->type_info == CATCH_ALL_TYPE))
+     extra = 0;
+ 
+   info->num_handlers[index] = count + extra;
+   info->handlers[index] = (handler_info **) malloc ((count + extra) 
+   						    * sizeof (handler_info **));
+ 
+   /* First put all our handlers into the list.  */
+   ptr = get_first_handler (block);
+   for (x = 0; x < count; x++)
+     {
+       info->handlers[index][x] = ptr;
+       ptr = ptr->next;
+     }
+ 
+   /* Now add all the outer region handlers, if they aren't they same as 
+      one of the types in the current block.  We won't worry about
+      derived types yet, we'll just look for the exact type.  */
+   for (y =0, x = 0; x < extra ; x++)
+     {
+       int i, ok;
+       ok = 1;
+       /* Check to see if we have a type duplication.  */
+       for (i = 0; i < count; i++)
+         if (info->handlers[index][i]->type_info == extra_handlers[x]->type_info)
+ 	  {
+ 	    ok = 0;
+ 	    /* Record one less handler.  */
+ 	    (info->num_handlers[index])--;
+ 	    break;
+ 	  }
+       if (ok)
+         {
+ 	  info->handlers[index][y + count] = extra_handlers[x];
+ 	  y++;
+ 	}
+     }
+ }
+ 
+ /* This function will allocate and initialize an eh_nesting_info structure. 
+    It returns a pointer to the completed data structure.  If there are
+    no exception regions, a NULL value is returned.  */
+ eh_nesting_info *
+ init_eh_nesting_info ()
+ {
+   int *nested_eh_region;
+   int region_count = 0;
+   rtx eh_note = NULL_RTX;
+   eh_nesting_info *info;
+   rtx insn;
+   int x;
+ 
+   info = (eh_nesting_info *) malloc (sizeof (eh_nesting_info));
+   info->region_index = (int *) malloc ((max_label_num () + 1) * sizeof (int));
+   bzero ((char *) info->region_index, (max_label_num () + 1) * sizeof (int));
+ 
+   nested_eh_region = (int *) alloca ((max_label_num () + 1) * sizeof (int));
+   bzero ((char *) nested_eh_region, (max_label_num () + 1) * sizeof (int));
+ 
+   /* Create the nested_eh_region list.  If indexed with a block number, it 
+      returns the block number of the next outermost region, if any. 
+      We can count the number of regions and initialize the region_index
+      vector at the same time.  */
+   for (insn = get_insns(); insn; insn = NEXT_INSN (insn))
+     {
+       if (GET_CODE (insn) == NOTE)
+ 	{
+           if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
+             {
+ 	      int block = NOTE_BLOCK_NUMBER (insn);
+ 	      region_count++;
+ 	      info->region_index[block] = region_count;
+               if (eh_note)
+                 nested_eh_region [block] =
+                                      NOTE_BLOCK_NUMBER (XEXP (eh_note, 0));
+               else
+                 nested_eh_region [block] = 0;
+               eh_note = gen_rtx_EXPR_LIST (VOIDmode, insn, eh_note);
+             }
+           else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END)
+             eh_note = XEXP (eh_note, 1);
+         }
+     }
+   
+   /* If there are no regions, wrap it up now.  */
+   if (region_count == 0)
+     {
+       free (info->region_index);
+       free (info);
+       return NULL;
+     }
+ 
+   region_count++;
+   info->handlers = (handler_info ***) malloc (region_count 
+ 					      * sizeof (handler_info ***));
+   info->num_handlers = (int *) malloc (region_count * sizeof (int));
+   info->outer_index = (int *) malloc (region_count * sizeof (int));
+ 
+   bzero ((char *) info->handlers, region_count * sizeof (rtx *));
+   bzero ((char *) info->num_handlers, region_count * sizeof (int));
+   bzero ((char *) info->outer_index, region_count * sizeof (int));
+ 
+  /* Now initialize the handler lists for all exception blocks.  */
+   for (x = 0; x <= max_label_num (); x++)
+     {
+       if (info->region_index[x] != 0)
+ 	process_nestinfo (x, info, nested_eh_region);
+     }
+   info->region_count = region_count;
+   return info;
+ }
+ 
+ 
+ /* This function is used to retreive the vector of handlers which 
+    can be reached by a given insn in a given exception region.
+    BLOCK is the exception block the insn is in.
+    INFO is the eh_nesting_info structure.
+    INSN is the (optional) insn within the block.  If insn is not NULL_RTX,
+    it may contain reg notes which modify its throwing behavior, and
+    these will be obeyed.  If NULL_RTX is passed, then we simply return the
+    handlers for block.
+    HANDLERS is the address of a pointer to a vector of handler_info pointers.
+    Upon return, this will have the handlers which can be reached by block.
+    This function returns the number of elements in the handlers vector.  */
+ int 
+ reachable_handlers (block, info, insn, handlers)
+      int block;
+      eh_nesting_info *info;
+      rtx insn ;
+      handler_info ***handlers;
+ {
+   int index = 0;
+   *handlers = NULL;
+ 
+   if (info == NULL)
+     return 0;
+   if (block > 0)
+     index = info->region_index[block];
+ 
+   if (insn && GET_CODE (insn) == CALL_INSN)
+     {
+       /* RETHROWs specify a region number from which we are going to rethrow.
+ 	 This means we wont pass control to handlers in the specified
+ 	 region, but rather any region OUTSIDE the specified region.
+ 	 We accomplish this by setting block to the outer_index of the
+ 	 specified region.  */
+       rtx note = find_reg_note (insn, REG_EH_RETHROW, NULL_RTX);
+       if (note)
+ 	{
+           index = eh_region_from_symbol (XEXP (note, 0));
+ 	  index = info->region_index[index];
+ 	  if (index)
+ 	    index = info->outer_index[index];
+ 	}
+       else
+         {
+ 	  /* If there is no rethrow, we look for a REG_EH_REGION, and
+ 	     we'll throw from that block.  A value of 0 or less
+ 	     indicates that this insn cannot throw.  */
+ 	  note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
+ 	  if (note)
+ 	    {
+ 	      int b = XINT (XEXP (note, 0), 0);
+ 	      if (b <= 0)
+ 	        index = 0;
+ 	      else
+ 		index = info->region_index[b];
+ 	    }
+ 	}
+     }
+   /* If we reach this point, and index is 0, there is no throw.  */
+   if (index == 0)
+     return 0;
+   
+   *handlers = info->handlers[index];
+   return info->num_handlers[index];
+ }
+ 
+ 
+ /* This function will free all memory associated with the eh_nesting info.  */
+ 
+ void 
+ free_eh_nesting_info (info)
+      eh_nesting_info *info;
+ {
+   int x;
+   if (info != NULL)
+     {
+       if (info->region_index)
+         free (info->region_index);
+       if (info->num_handlers)
+         free (info->num_handlers);
+       if (info->outer_index)
+         free (info->outer_index);
+       if (info->handlers)
+         {
+ 	  for (x = 0; x < info->region_count; x++)
+ 	    if (info->handlers[x])
+ 	      free (info->handlers[x]);
+ 	  free (info->handlers);
+ 	}
+     }
+ }

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