except.h (eh_nesting_info): Add new structure defintion.
Tue Aug 10 10:47:42 EDT 1999 Andrew MacLeod <amacleod@cygnus.com> * 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. From-SVN: r28647
This commit is contained in:
parent
a8688bd6e9
commit
1ef1bf063b
|
@ -1,3 +1,38 @@
|
|||
Tue Aug 10 10:47:42 EDT 1999 Andrew MacLeod <amacleod@cygnus.com>
|
||||
|
||||
* 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.
|
||||
|
||||
Tue Aug 10 10:39:31 EDT 1999 Andrew MacLeod <amacleod@cygnus.com>
|
||||
|
||||
* flow.c (split_edge): Set JUMP_LABEL field.
|
||||
|
|
340
gcc/except.c
340
gcc/except.c
|
@ -677,8 +677,9 @@ receive_exception_label (handler_label)
|
|||
|
||||
struct func_eh_entry
|
||||
{
|
||||
int range_number; /* EH region number from EH NOTE insn's */
|
||||
rtx rethrow_label; /* Label for rethrow */
|
||||
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;
|
||||
};
|
||||
|
||||
|
@ -981,7 +982,7 @@ rethrow_symbol_map (sym, map)
|
|||
{
|
||||
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;
|
||||
function_eh_regions[x].rethrow_ref = 1;
|
||||
}
|
||||
return function_eh_regions[x].rethrow_label;
|
||||
}
|
||||
|
@ -994,8 +995,8 @@ rethrow_used (region)
|
|||
{
|
||||
if (flag_new_exceptions)
|
||||
{
|
||||
rtx lab = function_eh_regions[find_func_region (region)].rethrow_label;
|
||||
return (SYMBOL_REF_USED (lab));
|
||||
int ret = function_eh_regions[find_func_region (region)].rethrow_ref;
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -1900,23 +1901,24 @@ expand_rethrow (label)
|
|||
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;
|
||||
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 ();
|
||||
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,
|
||||
|
||||
/* Mark the label/symbol on the call. */
|
||||
REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EH_RETHROW, label,
|
||||
REG_NOTES (insn));
|
||||
emit_barrier ();
|
||||
emit_barrier ();
|
||||
}
|
||||
else
|
||||
emit_jump (label);
|
||||
|
@ -2062,7 +2064,7 @@ output_exception_table_entry (file, n)
|
|||
if (rethrow != NULL_RTX && !flag_new_exceptions)
|
||||
rethrow = NULL_RTX;
|
||||
if (rethrow != NULL_RTX && handler == NULL)
|
||||
if (! SYMBOL_REF_USED (rethrow))
|
||||
if (! function_eh_regions[index].rethrow_ref)
|
||||
rethrow = NULL_RTX;
|
||||
|
||||
|
||||
|
@ -2373,9 +2375,14 @@ static int
|
|||
can_throw (insn)
|
||||
rtx insn;
|
||||
{
|
||||
/* Calls can always potentially throw exceptions. */
|
||||
/* 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)
|
||||
return 1;
|
||||
{
|
||||
rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
|
||||
if (!note || XINT (XEXP (note, 0), 0) > 0)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (asynchronous_exceptions)
|
||||
{
|
||||
|
@ -2416,9 +2423,8 @@ scan_region (insn, n, delete_outer)
|
|||
/* 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)))
|
||||
if (rethrow_used (n))
|
||||
delete = 0;
|
||||
|
||||
if (insn == NULL_RTX
|
||||
|
@ -2533,6 +2539,53 @@ exception_optimize ()
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
|
||||
|
@ -2853,4 +2906,249 @@ in_same_eh_region (insn1, insn2)
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
45
gcc/except.h
45
gcc/except.h
|
@ -266,6 +266,11 @@ rtx rethrow_symbol_map PROTO((rtx, rtx (*)(rtx)));
|
|||
|
||||
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));
|
||||
|
@ -278,6 +283,46 @@ struct handler_info *get_first_handler PROTO((int));
|
|||
|
||||
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));
|
||||
|
||||
/* Initialization for the per-function EH data. */
|
||||
|
|
62
gcc/flow.c
62
gcc/flow.c
|
@ -867,6 +867,7 @@ make_edges (label_value_list, bb_eh_end)
|
|||
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;
|
||||
|
@ -976,41 +977,19 @@ make_edges (label_value_list, bb_eh_end)
|
|||
if (code == CALL_INSN || asynchronous_exceptions)
|
||||
{
|
||||
int is_call = (code == CALL_INSN ? EDGE_ABNORMAL_CALL : 0);
|
||||
handler_info *ptr;
|
||||
handler_info **handler_list;
|
||||
int eh_region = -1;
|
||||
int num;
|
||||
|
||||
/* 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? */
|
||||
if (eh_list)
|
||||
eh_region = NOTE_BLOCK_NUMBER (XEXP (eh_list, 0));
|
||||
|
||||
x = find_reg_note (insn, REG_EH_RETHROW, 0);
|
||||
if (!x)
|
||||
x = find_reg_note (insn, REG_EH_REGION, 0);
|
||||
if (x)
|
||||
num = reachable_handlers (eh_region, eh_nest_info,
|
||||
insn, &handler_list);
|
||||
for ( ; num > 0; num--)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
make_label_edge (bb, handler_list[num - 1]->handler_label,
|
||||
EDGE_ABNORMAL | EDGE_EH | is_call);
|
||||
}
|
||||
|
||||
if (code == CALL_INSN && nonlocal_goto_handler_labels)
|
||||
|
@ -1022,10 +1001,13 @@ make_edges (label_value_list, bb_eh_end)
|
|||
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);
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1050,6 +1032,7 @@ make_edges (label_value_list, bb_eh_end)
|
|||
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
|
||||
|
@ -1615,6 +1598,8 @@ delete_eh_regions ()
|
|||
{
|
||||
rtx insn;
|
||||
|
||||
update_rethrow_references ();
|
||||
|
||||
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
|
||||
if (GET_CODE (insn) == NOTE)
|
||||
{
|
||||
|
@ -1622,8 +1607,9 @@ delete_eh_regions ()
|
|||
(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)
|
||||
/* 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;
|
||||
|
|
12
gcc/rtl.h
12
gcc/rtl.h
|
@ -344,13 +344,13 @@ typedef struct rtvec_def{
|
|||
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
|
||||
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. */
|
||||
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)
|
||||
|
|
Loading…
Reference in New Issue