diff options
author | amacleod <amacleod@138bc75d-0d04-0410-961f-82ee72b054a4> | 1999-08-10 16:19:16 +0000 |
---|---|---|
committer | amacleod <amacleod@138bc75d-0d04-0410-961f-82ee72b054a4> | 1999-08-10 16:19:16 +0000 |
commit | da5038a3ba3d077ca2bfe548b31a4822ed2f0e8d (patch) | |
tree | 2b4a46a35a3de3f7ea944875d45ee6b88e31d370 /gcc/except.c | |
parent | 829aa0d6c5592afbc93bf4a1b9e0f7b0667c0446 (diff) | |
download | gcc-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.c | 340 |
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); + } + } +} |