aboutsummaryrefslogtreecommitdiff
path: root/gcc/except.c
diff options
context:
space:
mode:
authorJan Hubicka <jh@suse.cz>2009-07-12 14:07:35 +0200
committerJan Hubicka <hubicka@gcc.gnu.org>2009-07-12 12:07:35 +0000
commitf645e9a2bfbb081915758e0538164bd7c65d6def (patch)
tree664bba0151c5567ef526a334b8502130112e2e2b /gcc/except.c
parent06066f92aaea9e9b0fff53a693b300bb9aa1121a (diff)
downloadgcc-f645e9a2bfbb081915758e0538164bd7c65d6def.zip
gcc-f645e9a2bfbb081915758e0538164bd7c65d6def.tar.gz
gcc-f645e9a2bfbb081915758e0538164bd7c65d6def.tar.bz2
re PR tree-optimization/40585 (tracer duplicates blocks w/o adjusting EH tree)
PR tree-optimization/40585 * except.c (expand_resx_expr): When there already is resume instruction, produce linked list. (build_post_landing_pads): Assert that resume is empty. (connect_post_landing_pads): Handle resume lists. (dump_eh_tree): Dump resume list. From-SVN: r149530
Diffstat (limited to 'gcc/except.c')
-rw-r--r--gcc/except.c107
1 files changed, 66 insertions, 41 deletions
diff --git a/gcc/except.c b/gcc/except.c
index 4fce026..06e5529 100644
--- a/gcc/except.c
+++ b/gcc/except.c
@@ -440,12 +440,16 @@ void
expand_resx_expr (tree exp)
{
int region_nr = TREE_INT_CST_LOW (TREE_OPERAND (exp, 0));
+ rtx insn;
struct eh_region_d *reg = VEC_index (eh_region,
cfun->eh->region_array, region_nr);
- gcc_assert (!reg->resume);
do_pending_stack_adjust ();
- reg->resume = emit_jump_insn (gen_rtx_RESX (VOIDmode, region_nr));
+ insn = emit_jump_insn (gen_rtx_RESX (VOIDmode, region_nr));
+ if (reg->resume)
+ reg->resume = gen_rtx_INSN_LIST (VOIDmode, insn, reg->resume);
+ else
+ reg->resume = insn;
emit_barrier ();
}
@@ -2012,6 +2016,7 @@ build_post_landing_pads (void)
/* We delay the generation of the _Unwind_Resume until we generate
landing pads. We emit a marker here so as to get good control
flow data in the meantime. */
+ gcc_assert (!region->resume);
region->resume
= emit_jump_insn (gen_rtx_RESX (VOIDmode, region->region_number));
emit_barrier ();
@@ -2040,6 +2045,7 @@ build_post_landing_pads (void)
/* We delay the generation of the _Unwind_Resume until we generate
landing pads. We emit a marker here so as to get good control
flow data in the meantime. */
+ gcc_assert (!region->resume);
region->resume
= emit_jump_insn (gen_rtx_RESX (VOIDmode, region->region_number));
emit_barrier ();
@@ -2080,6 +2086,7 @@ connect_post_landing_pads (void)
struct eh_region_d *outer;
rtx seq;
rtx barrier;
+ rtx resume_list;
region = VEC_index (eh_region, cfun->eh->region_array, i);
/* Mind we don't process a region more than once. */
@@ -2088,7 +2095,7 @@ connect_post_landing_pads (void)
/* If there is no RESX, or it has been deleted by flow, there's
nothing to fix up. */
- if (! region->resume || INSN_DELETED_P (region->resume))
+ if (! region->resume)
continue;
/* Search for another landing pad in this function. */
@@ -2096,46 +2103,55 @@ connect_post_landing_pads (void)
if (outer->post_landing_pad)
break;
- start_sequence ();
-
- if (outer)
+ for (resume_list = region->resume; resume_list;
+ resume_list = (GET_CODE (resume_list) == INSN_LIST
+ ? XEXP (resume_list, 1) : NULL_RTX))
{
- edge e;
- basic_block src, dest;
-
- emit_jump (outer->post_landing_pad);
- src = BLOCK_FOR_INSN (region->resume);
- dest = BLOCK_FOR_INSN (outer->post_landing_pad);
- while (EDGE_COUNT (src->succs) > 0)
- remove_edge (EDGE_SUCC (src, 0));
- e = make_edge (src, dest, 0);
- e->probability = REG_BR_PROB_BASE;
- e->count = src->count;
- }
- else
- {
- emit_library_call (unwind_resume_libfunc, LCT_THROW,
- VOIDmode, 1, crtl->eh.exc_ptr, ptr_mode);
-
- /* What we just emitted was a throwing libcall, so it got a
- barrier automatically added after it. If the last insn in
- the libcall sequence isn't the barrier, it's because the
- target emits multiple insns for a call, and there are insns
- after the actual call insn (which are redundant and would be
- optimized away). The barrier is inserted exactly after the
- call insn, so let's go get that and delete the insns after
- it, because below we need the barrier to be the last insn in
- the sequence. */
- delete_insns_since (NEXT_INSN (last_call_insn ()));
- }
+ rtx resume = (GET_CODE (resume_list) == INSN_LIST
+ ? XEXP (resume_list, 0) : resume_list);
+ if (INSN_DELETED_P (resume))
+ continue;
+ start_sequence ();
- seq = get_insns ();
- end_sequence ();
- barrier = emit_insn_before (seq, region->resume);
- /* Avoid duplicate barrier. */
- gcc_assert (BARRIER_P (barrier));
- delete_insn (barrier);
- delete_insn (region->resume);
+ if (outer)
+ {
+ edge e;
+ basic_block src, dest;
+
+ emit_jump (outer->post_landing_pad);
+ src = BLOCK_FOR_INSN (resume);
+ dest = BLOCK_FOR_INSN (outer->post_landing_pad);
+ while (EDGE_COUNT (src->succs) > 0)
+ remove_edge (EDGE_SUCC (src, 0));
+ e = make_edge (src, dest, 0);
+ e->probability = REG_BR_PROB_BASE;
+ e->count = src->count;
+ }
+ else
+ {
+ emit_library_call (unwind_resume_libfunc, LCT_THROW,
+ VOIDmode, 1, crtl->eh.exc_ptr, ptr_mode);
+
+ /* What we just emitted was a throwing libcall, so it got a
+ barrier automatically added after it. If the last insn in
+ the libcall sequence isn't the barrier, it's because the
+ target emits multiple insns for a call, and there are insns
+ after the actual call insn (which are redundant and would be
+ optimized away). The barrier is inserted exactly after the
+ call insn, so let's go get that and delete the insns after
+ it, because below we need the barrier to be the last insn in
+ the sequence. */
+ delete_insns_since (NEXT_INSN (last_call_insn ()));
+ }
+
+ seq = get_insns ();
+ end_sequence ();
+ barrier = emit_insn_before (seq, resume);
+ /* Avoid duplicate barrier. */
+ gcc_assert (BARRIER_P (barrier));
+ delete_insn (barrier);
+ delete_insn (resume);
+ }
/* ??? From tree-ssa we can wind up with catch regions whose
label is not instantiated, but whose resx is present. Now
@@ -4419,6 +4435,15 @@ dump_eh_tree (FILE * out, struct function *fun)
}
if (i->resume)
{
+ rtx resume_list = i->resume;
+ fprintf (out, " resume:");
+ while (GET_CODE (resume_list) == INSN_LIST)
+ {
+ fprintf (out, "%i,", INSN_UID (XEXP (resume_list, 0)));
+ if (NOTE_P (XEXP (resume_list, 0)))
+ fprintf (out, " (deleted)");
+ resume_list = XEXP (resume_list, 1);
+ }
fprintf (out, " resume:%i", INSN_UID (i->resume));
if (NOTE_P (i->resume))
fprintf (out, " (deleted)");