[CVS source] bootstrap failure on Solaris-2.[56]

Andrew Macleod amacleod@cygnus.com
Thu Aug 5 05:42:00 GMT 1999


>> 
>> With the following flags, bootstrapping current CVS tree fails on
>> Solaris.
>> 
>> 	BOOT_CFLAGS='-g -O2 -fnew-abi -fnew-exceptions'
>> 	BOOT_CXXFLAGS='-g -O2 -fnew-abi -fnew-exceptions -fstrict-aliasing'
>> 
>> -- Gaby

I have a flow graph patch for -fnew-exceptions which is going to be
checked in very shortly.  I havent checked it in yet because I haven't
been able to get a bootstrappable egcs yet to verify it. Im pretty sure
it will bootstrap (it use to), in any case, give this a try.
Its all approved and will be checked in when I can verify it
bootstraps. If you try it and it does bootstrap, let me know and I'll
check it in.

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);
+ 	}
+     }
+ }


More information about the Gcc-bugs mailing list