-
-/* Generate the code to actually handle exceptions, which will follow the
- landing pads. */
-
-static void
-build_post_landing_pads (void)
-{
- int i;
-
- for (i = cfun->eh->last_region_number; i > 0; --i)
- {
- struct eh_region *region;
- rtx seq;
-
- region = VEC_index (eh_region, cfun->eh->region_array, i);
- /* Mind we don't process a region more than once. */
- if (!region || region->region_number != i)
- continue;
-
- switch (region->type)
- {
- case ERT_TRY:
- /* ??? Collect the set of all non-overlapping catch handlers
- all the way up the chain until blocked by a cleanup. */
- /* ??? Outer try regions can share landing pads with inner
- try regions if the types are completely non-overlapping,
- and there are no intervening cleanups. */
-
- region->post_landing_pad = gen_label_rtx ();
-
- start_sequence ();
-
- emit_label (region->post_landing_pad);
-
- /* ??? It is mighty inconvenient to call back into the
- switch statement generation code in expand_end_case.
- Rapid prototyping sez a sequence of ifs. */
- {
- struct eh_region *c;
- for (c = region->u.try.catch; c ; c = c->u.catch.next_catch)
- {
- if (c->u.catch.type_list == NULL)
- emit_jump (c->label);
- else
- {
- /* Need for one cmp/jump per type caught. Each type
- list entry has a matching entry in the filter list
- (see assign_filter_values). */
- tree tp_node = c->u.catch.type_list;
- tree flt_node = c->u.catch.filter_list;
-
- for (; tp_node; )
- {
- emit_cmp_and_jump_insns
- (cfun->eh->filter,
- GEN_INT (tree_low_cst (TREE_VALUE (flt_node), 0)),
- EQ, NULL_RTX,
- targetm.eh_return_filter_mode (), 0, c->label);
-
- tp_node = TREE_CHAIN (tp_node);
- flt_node = TREE_CHAIN (flt_node);
- }
- }
- }
- }
-
- /* 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. */
- region->resume
- = emit_jump_insn (gen_rtx_RESX (VOIDmode, region->region_number));
- emit_barrier ();
-
- seq = get_insns ();
- end_sequence ();
-
- emit_to_new_bb_before (seq, region->u.try.catch->label);
-
- break;
-
- case ERT_ALLOWED_EXCEPTIONS:
- region->post_landing_pad = gen_label_rtx ();
-
- start_sequence ();
-
- emit_label (region->post_landing_pad);
-
- emit_cmp_and_jump_insns (cfun->eh->filter,
- GEN_INT (region->u.allowed.filter),
- EQ, NULL_RTX,
- targetm.eh_return_filter_mode (), 0, region->label);
-
- /* 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. */
- region->resume
- = emit_jump_insn (gen_rtx_RESX (VOIDmode, region->region_number));
- emit_barrier ();
-
- seq = get_insns ();
- end_sequence ();
-
- emit_to_new_bb_before (seq, region->label);
- break;
-
- case ERT_CLEANUP:
- case ERT_MUST_NOT_THROW:
- region->post_landing_pad = region->label;
- break;
-
- case ERT_CATCH:
- case ERT_THROW:
- /* Nothing to do. */
- break;
-
- default:
- gcc_unreachable ();
- }
- }
-}
-
-/* Replace RESX patterns with jumps to the next handler if any, or calls to
- _Unwind_Resume otherwise. */
-
-static void
-connect_post_landing_pads (void)
-{
- int i;
-
- for (i = cfun->eh->last_region_number; i > 0; --i)
- {
- struct eh_region *region;
- struct eh_region *outer;
- rtx seq;
- rtx barrier;
-
- region = VEC_index (eh_region, cfun->eh->region_array, i);
- /* Mind we don't process a region more than once. */
- if (!region || region->region_number != i)
- continue;
-
- /* 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))
- continue;
-
- /* Search for another landing pad in this function. */
- for (outer = region->outer; outer ; outer = outer->outer)
- if (outer->post_landing_pad)
- break;
-
- start_sequence ();
-
- if (outer)
- {
- 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, cfun->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, region->resume);
- /* Avoid duplicate barrier. */
- gcc_assert (BARRIER_P (barrier));
- delete_insn (barrier);
- delete_insn (region->resume);
-
- /* ??? From tree-ssa we can wind up with catch regions whose
- label is not instantiated, but whose resx is present. Now
- that we've dealt with the resx, kill the region. */
- if (region->label == NULL && region->type == ERT_CLEANUP)
- remove_eh_handler (region);
- }
-}
-