summaryrefslogtreecommitdiff
path: root/gcc/except.c
diff options
context:
space:
mode:
authoramacleod <amacleod@138bc75d-0d04-0410-961f-82ee72b054a4>1999-08-10 16:19:16 +0000
committeramacleod <amacleod@138bc75d-0d04-0410-961f-82ee72b054a4>1999-08-10 16:19:16 +0000
commitda5038a3ba3d077ca2bfe548b31a4822ed2f0e8d (patch)
tree2b4a46a35a3de3f7ea944875d45ee6b88e31d370 /gcc/except.c
parent829aa0d6c5592afbc93bf4a1b9e0f7b0667c0446 (diff)
downloadgcc-da5038a3ba3d077ca2bfe548b31a4822ed2f0e8d.tar.gz
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@28647 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/except.c')
-rw-r--r--gcc/except.c340
1 files changed, 319 insertions, 21 deletions
diff --git a/gcc/except.c b/gcc/except.c
index 40e912f9767..952021bbdcc 100644
--- a/gcc/except.c
+++ b/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);
+ }
+ }
+}