[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