basic-block.h (flow_delete_block_noexpunge): Declare.

* basic-block.h (flow_delete_block_noexpunge): Declare.
	(expunge_block_nocompact): Declare.
	* cfg.c (expunge_block_nocompact): Split out from ...
	(expunge_block): ... here.
	* cfgrtl.c (can_delete_label_p): Don't use exception_handler_labels.
	(flow_delete_block_noexpunge): Split out from ...
	(flow_delete_block): ... here.
	* cfgcleanup.c (delete_unreachable_blocks): Compact while
	removing dead blocks.
	* except.c (exception_handler_labels): Remove.
	(exception_handler_label_map): New.
	(struct eh_region): Add aka member.
	(mark_ehl_map_entry, mark_ehl_map, free_region): New.
	(ehl_hash, ehl_eq, ehl_free, add_ehl_entry): New.
	(for_each_eh_label, for_each_eh_label_1): New.
	(init_eh): Register exception_handler_label_map.
	(free_eh_status): Use free_region.
	(find_exception_handler_labels): Use the map, not the list.
	(remove_exception_handler_label): Likewise.
	(maybe_remove_eh_handler): Likewise.
	(remove_eh_handler): Use the region aka bitmap.
	* except.h (exception_handler_labels): Remove.
	(for_each_eh_label): Declare.
	* jump.c (rebuild_jump_labels): Don't check exception_handler_labels.
	* loop.c (invalidate_loops_containing_label): New.
	(find_and_verify_loops): Use it.  Use for_each_eh_label.
	* sched-rgn.c (is_cfg_nonregular): Use
	current_function_has_exception_handlers.

From-SVN: r52100
This commit is contained in:
Richard Henderson 2002-04-09 17:15:58 -07:00 committed by Richard Henderson
parent 4fc4e47839
commit 6a58eee93d
10 changed files with 297 additions and 96 deletions

View File

@ -1,3 +1,34 @@
2002-04-09 Richard Henderson <rth@redhat.com>
* basic-block.h (flow_delete_block_noexpunge): Declare.
(expunge_block_nocompact): Declare.
* cfg.c (expunge_block_nocompact): Split out from ...
(expunge_block): ... here.
* cfgrtl.c (can_delete_label_p): Don't use exception_handler_labels.
(flow_delete_block_noexpunge): Split out from ...
(flow_delete_block): ... here.
* cfgcleanup.c (delete_unreachable_blocks): Compact while
removing dead blocks.
* except.c (exception_handler_labels): Remove.
(exception_handler_label_map): New.
(struct eh_region): Add aka member.
(mark_ehl_map_entry, mark_ehl_map, free_region): New.
(ehl_hash, ehl_eq, ehl_free, add_ehl_entry): New.
(for_each_eh_label, for_each_eh_label_1): New.
(init_eh): Register exception_handler_label_map.
(free_eh_status): Use free_region.
(find_exception_handler_labels): Use the map, not the list.
(remove_exception_handler_label): Likewise.
(maybe_remove_eh_handler): Likewise.
(remove_eh_handler): Use the region aka bitmap.
* except.h (exception_handler_labels): Remove.
(for_each_eh_label): Declare.
* jump.c (rebuild_jump_labels): Don't check exception_handler_labels.
* loop.c (invalidate_loops_containing_label): New.
(find_and_verify_loops): Use it. Use for_each_eh_label.
* sched-rgn.c (is_cfg_nonregular): Use
current_function_has_exception_handlers.
2002-04-09 Richard Henderson <rth@redhat.com>
* sbitmap.c (sbitmap_union_of_diff, sbitmap_a_and_b, sbitmap_a_xor_b,

View File

@ -1,5 +1,5 @@
/* Define control and data flow tables, and regsets.
Copyright (C) 1987, 1997, 1998, 1999, 2000, 2001
Copyright (C) 1987, 1997, 1998, 1999, 2000, 2001, 2002
Free Software Foundation, Inc.
This file is part of GCC.
@ -316,6 +316,7 @@ extern void redirect_edge_pred PARAMS ((edge, basic_block));
extern basic_block create_basic_block_structure PARAMS ((int, rtx, rtx, rtx));
extern basic_block create_basic_block PARAMS ((int, rtx, rtx));
extern int flow_delete_block PARAMS ((basic_block));
extern int flow_delete_block_noexpunge PARAMS ((basic_block));
extern void clear_bb_flags PARAMS ((void));
extern void merge_blocks_nomove PARAMS ((basic_block, basic_block));
extern void tidy_fallthru_edge PARAMS ((edge, basic_block,
@ -637,6 +638,7 @@ extern void debug_regset PARAMS ((regset));
extern void allocate_reg_life_data PARAMS ((void));
extern void allocate_bb_life_data PARAMS ((void));
extern void expunge_block PARAMS ((basic_block));
extern void expunge_block_nocompact PARAMS ((basic_block));
extern basic_block alloc_block PARAMS ((void));
extern void find_unreachable_blocks PARAMS ((void));
extern int delete_noop_moves PARAMS ((rtx));

View File

@ -222,6 +222,17 @@ alloc_block ()
/* Remove block B from the basic block array and compact behind it. */
void
expunge_block_nocompact (b)
basic_block b;
{
/* Invalidate data to make bughunting easier. */
memset (b, 0, sizeof *b);
b->index = -3;
b->succ = (edge) first_deleted_block;
first_deleted_block = (basic_block) b;
}
void
expunge_block (b)
basic_block b;
@ -235,13 +246,10 @@ expunge_block (b)
x->index = i;
}
/* Invalidate data to make bughunting easier. */
memset (b, 0, sizeof *b);
b->index = -3;
basic_block_info->num_elements--;
n_basic_blocks--;
b->succ = (edge) first_deleted_block;
first_deleted_block = (basic_block) b;
basic_block_info->num_elements--;
expunge_block_nocompact (b);
}
/* Create an edge connecting SRC and DST with FLAGS optionally using

View File

@ -1,6 +1,6 @@
/* Control flow optimization code for GNU compiler.
Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
1999, 2000, 2001 Free Software Foundation, Inc.
1999, 2000, 2001, 2002 Free Software Foundation, Inc.
This file is part of GCC.
@ -1751,22 +1751,33 @@ try_optimize_cfg (mode)
static bool
delete_unreachable_blocks ()
{
int i;
int i, j;
bool changed = false;
find_unreachable_blocks ();
/* Delete all unreachable basic blocks. Count down so that we
don't interfere with the block renumbering that happens in
flow_delete_block. */
/* Delete all unreachable basic blocks. Do compaction concurrently,
as otherwise we can wind up with O(N^2) behaviour here when we
have oodles of dead code. */
for (i = n_basic_blocks - 1; i >= 0; --i)
for (i = j = 0; i < n_basic_blocks; ++i)
{
basic_block b = BASIC_BLOCK (i);
if (!(b->flags & BB_REACHABLE))
flow_delete_block (b), changed = true;
{
flow_delete_block_noexpunge (b);
expunge_block_nocompact (b);
changed = true;
}
else
{
BASIC_BLOCK (j) = b;
b->index = j++;
}
}
n_basic_blocks = j;
basic_block_info->num_elements = j;
if (changed)
tidy_fallthru_edges ();

View File

@ -1,6 +1,6 @@
/* Control flow graph manipulation code for GNU compiler.
Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
1999, 2000, 2001 Free Software Foundation, Inc.
1999, 2000, 2001, 2002 Free Software Foundation, Inc.
This file is part of GCC.
@ -102,8 +102,7 @@ can_delete_label_p (label)
/* User declared labels must be preserved. */
&& LABEL_NAME (label) == 0
&& !in_expr_list_p (forced_labels, label)
&& !in_expr_list_p (label_value_list, label)
&& !in_expr_list_p (exception_handler_labels, label));
&& !in_expr_list_p (label_value_list, label));
}
/* Delete INSN by patching it out. Return the next insn. */
@ -363,7 +362,7 @@ create_basic_block (index, head, end)
to post-process the stream to remove empty blocks, loops, ranges, etc. */
int
flow_delete_block (b)
flow_delete_block_noexpunge (b)
basic_block b;
{
int deleted_handler = 0;
@ -412,6 +411,15 @@ flow_delete_block (b)
b->pred = NULL;
b->succ = NULL;
return deleted_handler;
}
int
flow_delete_block (b)
basic_block b;
{
int deleted_handler = flow_delete_block_noexpunge (b);
/* Remove the basic block from the array, and compact behind it. */
expunge_block (b);

View File

@ -98,8 +98,15 @@ int (*lang_eh_type_covers) PARAMS ((tree a, tree b));
/* Map a type to a runtime object to match type. */
tree (*lang_eh_runtime_type) PARAMS ((tree));
/* A list of labels used for exception handlers. */
rtx exception_handler_labels;
/* A hash table of label to region number. */
struct ehl_map_entry
{
rtx label;
struct eh_region *region;
};
static htab_t exception_handler_label_map;
static int call_site_base;
static unsigned int sjlj_funcdef_number;
@ -126,6 +133,10 @@ struct eh_region
/* An identifier for this region. */
int region_number;
/* When a region is deleted, its parents inherit the REG_EH_REGION
numbers already assigned. */
bitmap aka;
/* Each region does exactly one thing. */
enum eh_region_type
{
@ -242,6 +253,10 @@ struct eh_status
static void mark_eh_region PARAMS ((struct eh_region *));
static int mark_ehl_map_entry PARAMS ((PTR *, PTR));
static void mark_ehl_map PARAMS ((void *));
static void free_region PARAMS ((struct eh_region *));
static int t2r_eq PARAMS ((const PTR,
const PTR));
@ -292,8 +307,15 @@ static void sjlj_emit_dispatch_table
PARAMS ((rtx, struct sjlj_lp_info *));
static void sjlj_build_landing_pads PARAMS ((void));
static hashval_t ehl_hash PARAMS ((const PTR));
static int ehl_eq PARAMS ((const PTR,
const PTR));
static void ehl_free PARAMS ((PTR));
static void add_ehl_entry PARAMS ((rtx,
struct eh_region *));
static void remove_exception_handler_label PARAMS ((rtx));
static void remove_eh_handler PARAMS ((struct eh_region *));
static int for_each_eh_label_1 PARAMS ((PTR *, PTR));
struct reachable_info;
@ -364,7 +386,7 @@ doing_eh (do_warn)
void
init_eh ()
{
ggc_add_rtx_root (&exception_handler_labels, 1);
ggc_add_root (&exception_handler_label_map, 1, 1, mark_ehl_map);
if (! flag_exceptions)
return;
@ -511,6 +533,25 @@ mark_eh_region (region)
ggc_mark_rtx (region->post_landing_pad);
}
static int
mark_ehl_map_entry (pentry, data)
PTR *pentry;
PTR data ATTRIBUTE_UNUSED;
{
struct ehl_map_entry *entry = *(struct ehl_map_entry **) pentry;
ggc_mark_rtx (entry->label);
return 1;
}
static void
mark_ehl_map (pp)
void *pp;
{
htab_t map = *(htab_t *) pp;
if (map)
htab_traverse (map, mark_ehl_map_entry, NULL);
}
void
mark_eh_status (eh)
struct eh_status *eh;
@ -572,6 +613,16 @@ mark_eh_status (eh)
ggc_mark_rtx (eh->sjlj_exit_after);
}
static inline void
free_region (r)
struct eh_region *r;
{
/* Note that the aka bitmap is freed by regset_release_memory. But if
we ever replace with a non-obstack implementation, this would be
the place to do it. */
free (r);
}
void
free_eh_status (f)
struct function *f;
@ -586,7 +637,7 @@ free_eh_status (f)
struct eh_region *r = eh->region_array[i];
/* Mind we don't free a region struct more than once. */
if (r && r->region_number == i)
free (r);
free_region (r);
}
free (eh->region_array);
}
@ -600,20 +651,20 @@ free_eh_status (f)
else if (r->next_peer)
{
next = r->next_peer;
free (r);
free_region (r);
r = next;
}
else
{
do {
next = r->outer;
free (r);
free_region (r);
r = next;
if (r == NULL)
goto tree_done;
} while (r->next_peer == NULL);
next = r->next_peer;
free (r);
free_region (r);
r = next;
}
}
@ -628,7 +679,12 @@ free_eh_status (f)
free (eh);
f->eh = NULL;
exception_handler_labels = NULL;
if (exception_handler_label_map)
{
htab_delete (exception_handler_label_map);
exception_handler_label_map = NULL;
}
}
@ -1312,13 +1368,50 @@ convert_from_eh_region_ranges ()
remove_unreachable_regions (insns);
}
static void
add_ehl_entry (label, region)
rtx label;
struct eh_region *region;
{
struct ehl_map_entry **slot, *entry;
LABEL_PRESERVE_P (label) = 1;
entry = (struct ehl_map_entry *) xmalloc (sizeof (*entry));
entry->label = label;
entry->region = region;
slot = (struct ehl_map_entry **)
htab_find_slot (exception_handler_label_map, entry, INSERT);
if (*slot)
abort ();
*slot = entry;
}
static void
ehl_free (pentry)
PTR pentry;
{
struct ehl_map_entry *entry = (struct ehl_map_entry *)pentry;
LABEL_PRESERVE_P (entry->label) = 0;
free (entry);
}
void
find_exception_handler_labels ()
{
rtx list = NULL_RTX;
int i;
free_EXPR_LIST_list (&exception_handler_labels);
if (exception_handler_label_map)
htab_empty (exception_handler_label_map);
else
{
/* ??? The expansion factor here (3/2) must be greater than the htab
occupancy factor (4/3) to avoid unnecessary resizing. */
exception_handler_label_map
= htab_create (cfun->eh->last_region_number * 3 / 2,
ehl_hash, ehl_eq, ehl_free);
}
if (cfun->eh->region_tree == NULL)
return;
@ -1336,15 +1429,13 @@ find_exception_handler_labels ()
lab = region->label;
if (lab)
list = alloc_EXPR_LIST (0, lab, list);
add_ehl_entry (lab, region);
}
/* For sjlj exceptions, need the return label to remain live until
after landing pad generation. */
if (USING_SJLJ_EXCEPTIONS && ! cfun->eh->built_landing_pads)
list = alloc_EXPR_LIST (0, return_label, list);
exception_handler_labels = list;
add_ehl_entry (return_label, NULL);
}
bool
@ -2430,28 +2521,50 @@ finish_eh_generation ()
cleanup_cfg (CLEANUP_PRE_LOOP);
}
static hashval_t
ehl_hash (pentry)
const PTR pentry;
{
struct ehl_map_entry *entry = (struct ehl_map_entry *) pentry;
/* 2^32 * ((sqrt(5) - 1) / 2) */
const hashval_t scaled_golden_ratio = 0x9e3779b9;
return CODE_LABEL_NUMBER (entry->label) * scaled_golden_ratio;
}
static int
ehl_eq (pentry, pdata)
const PTR pentry;
const PTR pdata;
{
struct ehl_map_entry *entry = (struct ehl_map_entry *) pentry;
struct ehl_map_entry *data = (struct ehl_map_entry *) pdata;
return entry->label == data->label;
}
/* This section handles removing dead code for flow. */
/* Remove LABEL from the exception_handler_labels list. */
/* Remove LABEL from exception_handler_label_map. */
static void
remove_exception_handler_label (label)
rtx label;
{
rtx *pl, l;
struct ehl_map_entry **slot, tmp;
/* If exception_handler_labels was not built yet,
/* If exception_handler_label_map was not built yet,
there is nothing to do. */
if (exception_handler_labels == NULL)
if (exception_handler_label_map == NULL)
return;
for (pl = &exception_handler_labels, l = *pl;
XEXP (l, 0) != label;
pl = &XEXP (l, 1), l = *pl)
continue;
tmp.label = label;
slot = (struct ehl_map_entry **)
htab_find_slot (exception_handler_label_map, &tmp, NO_INSERT);
if (! slot)
abort ();
*pl = XEXP (l, 1);
free_EXPR_LIST_node (l);
htab_clear_slot (exception_handler_label_map, (void **) slot);
}
/* Splice REGION from the region tree etc. */
@ -2462,16 +2575,29 @@ remove_eh_handler (region)
{
struct eh_region **pp, *p;
rtx lab;
int i;
/* For the benefit of efficiently handling REG_EH_REGION notes,
replace this region in the region array with its containing
region. Note that previous region deletions may result in
multiple copies of this region in the array, so we have to
search the whole thing. */
for (i = cfun->eh->last_region_number; i > 0; --i)
if (cfun->eh->region_array[i] == region)
cfun->eh->region_array[i] = region->outer;
multiple copies of this region in the array, so we have a
list of alternate numbers by which we are known. */
cfun->eh->region_array[region->region_number] = region->outer;
if (region->aka)
{
int i;
EXECUTE_IF_SET_IN_BITMAP (region->aka, 0, i,
{ cfun->eh->region_array[i] = region->outer; });
}
if (region->outer)
{
if (!region->outer->aka)
region->outer->aka = BITMAP_XMALLOC ();
if (region->aka)
bitmap_a_or_b (region->outer->aka, region->outer->aka, region->aka);
bitmap_set_bit (region->outer->aka, region->region_number);
}
if (cfun->eh->built_landing_pads)
lab = region->landing_pad;
@ -2526,7 +2652,7 @@ remove_eh_handler (region)
}
}
free (region);
free_region (region);
}
/* LABEL heads a basic block that is about to be deleted. If this
@ -2537,7 +2663,8 @@ void
maybe_remove_eh_handler (label)
rtx label;
{
int i;
struct ehl_map_entry **slot, tmp;
struct eh_region *region;
/* ??? After generating landing pads, it's not so simple to determine
if the region data is completely unused. One must examine the
@ -2546,27 +2673,50 @@ maybe_remove_eh_handler (label)
if (cfun->eh->built_landing_pads)
return;
for (i = cfun->eh->last_region_number; i > 0; --i)
tmp.label = label;
slot = (struct ehl_map_entry **)
htab_find_slot (exception_handler_label_map, &tmp, NO_INSERT);
if (! slot)
return;
region = (*slot)->region;
if (! region)
return;
/* Flow will want to remove MUST_NOT_THROW regions as unreachable
because there is no path to the fallback call to terminate.
But the region continues to affect call-site data until there
are no more contained calls, which we don't see here. */
if (region->type == ERT_MUST_NOT_THROW)
{
struct eh_region *region = cfun->eh->region_array[i];
if (region && region->label == label)
{
/* Flow will want to remove MUST_NOT_THROW regions as unreachable
because there is no path to the fallback call to terminate.
But the region continues to affect call-site data until there
are no more contained calls, which we don't see here. */
if (region->type == ERT_MUST_NOT_THROW)
{
remove_exception_handler_label (region->label);
region->label = NULL_RTX;
}
else
remove_eh_handler (region);
break;
}
htab_clear_slot (exception_handler_label_map, (void **) slot);
region->label = NULL_RTX;
}
else
remove_eh_handler (region);
}
/* Invokes CALLBACK for every exception handler label. Only used by old
loop hackery; should not be used by new code. */
void
for_each_eh_label (callback)
void (*callback) PARAMS ((rtx));
{
htab_traverse (exception_handler_label_map, for_each_eh_label_1,
(void *)callback);
}
static int
for_each_eh_label_1 (pentry, data)
PTR *pentry;
PTR data;
{
struct ehl_map_entry *entry = *(struct ehl_map_entry **)pentry;
void (*callback) PARAMS ((rtx)) = (void (*) PARAMS ((rtx))) data;
(*callback) (entry->label);
return 1;
}
/* This section describes CFG exception edges for flow. */

View File

@ -1,5 +1,5 @@
/* Exception Handling interface routines.
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002
Free Software Foundation, Inc.
Contributed by Mike Stump <mrs@cygnus.com>.
@ -83,8 +83,9 @@ extern void expand_eh_region_end_throw PARAMS ((tree));
destroying an object twice. */
extern void expand_eh_region_end_fixup PARAMS ((tree));
/* A list of labels used for exception handlers. */
extern rtx exception_handler_labels;
/* Invokes CALLBACK for every exception handler label. Only used by old
loop hackery; should not be used by new code. */
extern void for_each_eh_label PARAMS ((void (*) (rtx)));
/* Determine if the given INSN can throw an exception. */
extern bool can_throw_internal PARAMS ((rtx));

View File

@ -91,13 +91,6 @@ rebuild_jump_labels (f)
for (insn = forced_labels; insn; insn = XEXP (insn, 1))
if (GET_CODE (XEXP (insn, 0)) == CODE_LABEL)
LABEL_NUSES (XEXP (insn, 0))++;
/* Keep track of labels used for marking handlers for exception
regions; they cannot usually be deleted. */
for (insn = exception_handler_labels; insn; insn = XEXP (insn, 1))
if (GET_CODE (XEXP (insn, 0)) == CODE_LABEL)
LABEL_NUSES (XEXP (insn, 0))++;
}
/* Some old code expects exactly one BARRIER as the NEXT_INSN of a

View File

@ -235,6 +235,7 @@ FILE *loop_dump_stream;
/* Forward declarations. */
static void invalidate_loops_containing_label PARAMS ((rtx));
static void find_and_verify_loops PARAMS ((rtx, struct loops *));
static void mark_loop_jump PARAMS ((rtx, struct loop *));
static void prescan_loop PARAMS ((struct loop *));
@ -2609,6 +2610,17 @@ prescan_loop (loop)
}
}
/* Invalidate all loops containing LABEL. */
static void
invalidate_loops_containing_label (label)
rtx label;
{
struct loop *loop;
for (loop = uid_loop[INSN_UID (label)]; loop; loop = loop->outer)
loop->invalid = 1;
}
/* Scan the function looking for loops. Record the start and end of each loop.
Also mark as invalid loops any loops that contain a setjmp or are branched
to from outside the loop. */
@ -2695,23 +2707,12 @@ find_and_verify_loops (f, loops)
/* Any loop containing a label used in an initializer must be invalidated,
because it can be jumped into from anywhere. */
for (label = forced_labels; label; label = XEXP (label, 1))
{
for (loop = uid_loop[INSN_UID (XEXP (label, 0))];
loop; loop = loop->outer)
loop->invalid = 1;
}
invalidate_loops_containing_label (XEXP (label, 0));
/* Any loop containing a label used for an exception handler must be
invalidated, because it can be jumped into from anywhere. */
for (label = exception_handler_labels; label; label = XEXP (label, 1))
{
for (loop = uid_loop[INSN_UID (XEXP (label, 0))];
loop; loop = loop->outer)
loop->invalid = 1;
}
for_each_eh_label (invalidate_loops_containing_label);
/* Now scan all insn's in the function. If any JUMP_INSN branches into a
loop that it is not contained within, that loop is marked invalid.
@ -2735,11 +2736,7 @@ find_and_verify_loops (f, loops)
{
rtx note = find_reg_note (insn, REG_LABEL, NULL_RTX);
if (note)
{
for (loop = uid_loop[INSN_UID (XEXP (note, 0))];
loop; loop = loop->outer)
loop->invalid = 1;
}
invalidate_loops_containing_label (XEXP (note, 0));
}
if (GET_CODE (insn) != JUMP_INSN)

View File

@ -339,7 +339,7 @@ is_cfg_nonregular ()
/* If we have exception handlers, then we consider the cfg not well
structured. ?!? We should be able to handle this now that flow.c
computes an accurate cfg for EH. */
if (exception_handler_labels)
if (current_function_has_exception_handlers ())
return 1;
/* If we have non-jumping insns which refer to labels, then we consider