OSDN Git Service

Squash commit of EH in gimple
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 14 Sep 2009 19:18:58 +0000 (19:18 +0000)
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 14 Sep 2009 19:18:58 +0000 (19:18 +0000)
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@151696 138bc75d-0d04-0410-961f-82ee72b054a4

91 files changed:
gcc/ChangeLog
gcc/Makefile.in
gcc/ada/ChangeLog
gcc/ada/gcc-interface/misc.c
gcc/ada/gcc-interface/trans.c
gcc/ada/gcc-interface/utils.c
gcc/builtins.c
gcc/builtins.def
gcc/c-common.c
gcc/c-parser.c
gcc/calls.c
gcc/cfgbuild.c
gcc/cfgexpand.c
gcc/cfgrtl.c
gcc/cgraphunit.c
gcc/combine.c
gcc/cp/ChangeLog
gcc/cp/except.c
gcc/cp/optimize.c
gcc/cse.c
gcc/dce.c
gcc/dse.c
gcc/emit-rtl.c
gcc/except.c
gcc/except.h
gcc/expr.c
gcc/fold-const.c
gcc/fortran/ChangeLog
gcc/fortran/f95-lang.c
gcc/function.h
gcc/gcse.c
gcc/gengtype.c
gcc/gimple-iterator.c
gcc/gimple-low.c
gcc/gimple-pretty-print.c
gcc/gimple.c
gcc/gimple.def
gcc/gimple.h
gcc/gimplify.c
gcc/gsstruct.def
gcc/ipa-inline.c
gcc/ipa-pure-const.c
gcc/ipa-type-escape.c
gcc/ipa-utils.c
gcc/java/ChangeLog
gcc/java/builtins.c
gcc/java/decl.c
gcc/java/except.c
gcc/java/java-tree.h
gcc/libfuncs.h
gcc/lower-subreg.c
gcc/objc/ChangeLog
gcc/objc/objc-act.c
gcc/omp-low.c
gcc/optabs.c
gcc/passes.c
gcc/print-tree.c
gcc/recog.c
gcc/reload1.c
gcc/rtl.def
gcc/rtl.h
gcc/sese.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/eh/builtin1.C
gcc/testsuite/g++.dg/eh/builtin2.C
gcc/testsuite/g++.dg/eh/builtin3.C
gcc/testsuite/g++.dg/tree-ssa/ehcleanup-1.C
gcc/tree-cfg.c
gcc/tree-cfgcleanup.c
gcc/tree-dfa.c
gcc/tree-eh.c
gcc/tree-flow.h
gcc/tree-inline.c
gcc/tree-inline.h
gcc/tree-optimize.c
gcc/tree-pass.h
gcc/tree-pretty-print.c
gcc/tree-sra.c
gcc/tree-ssa-alias.c
gcc/tree-ssa-dce.c
gcc/tree-ssa-operands.c
gcc/tree-ssa-pre.c
gcc/tree-ssa-propagate.c
gcc/tree-ssa-sccvn.c
gcc/tree-ssa-sink.c
gcc/tree-ssa-structalias.c
gcc/tree.c
gcc/tree.def
gcc/tree.h
gcc/value-prof.c
gcc/vecprim.h

index 75333c1..cc04831 100644 (file)
@@ -1,3 +1,343 @@
+2009-09-14  Richard Henderson  <rth@redhat.com>
+
+       * except.h: Update declarations.
+       (struct pointer_map_t): Forward declare.
+       (ERT_UNKNOWN, ERT_THROW, ERT_CATCH): Remove.
+       (struct eh_landing_pad_d, eh_landing_pad): New.
+       (struct eh_catch_d, eh_catch): New.
+       (struct eh_region_d): Remove next_region_sharing_label, aka,
+       label, tree_label, landing_pad, post_landing_pad, resume,
+       may_contain_throw.  Rename region_number to index.  Remove
+       u.eh_catch, u.eh_throw.  Rename u.eh_try.eh_catch to first_catch.
+       Add u.must_not_throw, landing_pads, exc_ptr_reg, filter_reg.
+       (VEC(eh_landing_pad,gc)): New.
+       (struct eh_status): Remove last_region_number.  Add lp_array,
+       throw_stmt_table, ttype_data, ehspec_data.
+       (ehr_next, FOR_ALL_EH_REGION_AT): New.
+       (FOR_ALL_EH_REGION_FN, FOR_ALL_EH_REGION): New.
+       * except.c (lang_protect_cleanup_actions): Return tree.
+       (struct ehl_map_entry): Remove.
+       (init_eh_for_function): Push zero entries for region and lp_array.
+       (gen_eh_region): Add to region_array immediately.
+       (gen_eh_region_catch): Operate on eh_catch objects.
+       (gen_eh_landing_pad): New.
+       (get_eh_region_may_contain_throw, get_eh_region_tree_label): Remove.
+       (get_eh_region_no_tree_label, set_eh_region_tree_label): Remove.
+       (get_eh_region_from_number, get_eh_region_from_number_fn): New.
+       (get_eh_landing_pad_from_number_fn): New.
+       (get_eh_landing_pad_from_number): New.
+       (get_eh_region_from_lp_number_fn): New.
+       (get_eh_region_from_lp_number): New.
+       (expand_resx_stmt, note_eh_region_may_contain_throw): Remove.
+       (get_exception_pointer, get_exception_filter): Remove.
+       (collect_eh_region_array, can_be_reached_by_runtime): Remove.
+       (current_function_has_exception_handlers): Simplify.
+       (bring_to_root, eh_region_replaceable_by_p): Remove.
+       (replace_region, hash_type_list, hash_eh_region): Remove.
+       (eh_regions_equal_p, merge_peers, remove_unreachable_regions): Remove.
+       (label_to_region_map, num_eh_regions): Remove.
+       (get_next_region_sharing_label, must_not_throw_labels): Remove.
+       (find_exception_handler_labels): Remove.
+       (duplicate_eh_regions_0, find_prev_try): Remove.
+       (struct duplicate_eh_regions_data): New.
+       (duplicate_eh_regions_1): Rewrite.
+       (duplicate_eh_regions): Return a pointer map instead of an
+       integer offset.
+       (copy_eh_region_1, copy_eh_region, push_reachable_handler): Remove.
+       (redirect_eh_edge_to_label): Remove.
+       (eh_region_outermost): Rewrite using eh_region pointers
+       instead of integers.
+       (add_ttypes_entry): Update for ttype_data move to eh_status.
+       (add_ehspec_entry): Rewrite with VEC instead of varray.
+       (assign_filter_values): Likewise.  Export.
+       (build_post_landing_pads, connect_post_landing_pads): Remove.
+       (dw2_build_landing_pads): Rewrite to use lp_array.
+       (struct sjlj_lp_info, sjlj_find_directly_reachable_regions): Remove.
+       (sjlj_assign_call_site_values): Rewrite to use lp_array.
+       (sjlj_emit_dispatch_table, sjlj_build_landing_pads): Likewise.
+       (sjlj_mark_call_sites): Update for landing pad numbers.
+       (finish_eh_generation): Rewrite.
+       (gate_handle_eh): Do nothing for no eh tree.
+       (pass_rtl_eh): Move up near finish_eh_generation.
+       (remove_eh_landing_pad): New.
+       (remove_eh_handler): Export.
+       (remove_eh_region, remove_eh_handler_and_replace): Remove.
+       (for_each_eh_label): Rewrite to use lp_array.
+       (make_reg_eh_region_note): New.
+       (make_reg_eh_region_note_nothrow_nononlocal): New.
+       (insn_could_throw_p): New.
+       (copy_reg_eh_region_note_forward): New.
+       (copy_reg_eh_region_note_backward): New.
+       (check_handled, add_reachable_handler): Remove.
+       (reachable_next_level, foreach_reachable_handler): Remove.
+       (arh_to_landing_pad, arh_to_label, reachable_handlers): Remove.
+       (get_eh_region_and_lp_from_rtx): New.
+       (get_eh_region_from_rtx): New.
+       (can_throw_internal_1, can_throw_external_1): Remove.
+       (can_throw_internal): Use get_eh_region_from_rtx.
+       (can_throw_external): Use get_eh_region_and_lp_from_rtx.
+       (insn_nothrow_p, can_nonlocal_goto): New.
+       (expand_builtin_eh_common, expand_builtin_eh_pointer): New.
+       (expand_builtin_eh_filter, expand_builtin_eh_copy_values): New.
+       (add_action_record): Use VEC not varray.
+       (collect_one_action_chain): Update for eh_region changes.
+       (convert_to_eh_region_ranges): Make static.  Use VEC not varray.
+       Use get_eh_region_and_lp_from_rtx.
+       (gate_convert_to_eh_region_ranges): New.
+       (pass_convert_to_eh_region_ranges): Use it.
+       (push_uleb128, push_sleb128): Use VEC not varray.
+       (output_one_function_exception_table): Likewise.
+       (dump_eh_tree): Update for eh_region changes.
+       (verify_eh_tree): Likewise.
+       (verify_eh_region, default_init_unwind_resume_libfunc): Remove.
+       * tree-eh.c: Include target.h.
+       (add_stmt_to_eh_lp_fn): Rename from add_stmt_to_eh_region_fn.
+       Don't disallow GIMPLE_RESX; adjust argument check.
+       (add_stmt_to_eh_lp): Rename from add_stmt_to_eh_region.
+       (record_stmt_eh_region): Update for landing pad numbers;
+       generate a landing pad if necessary.
+       (remove_stmt_from_eh_lp): Rename from remove_stmt_from_eh_region.
+       (remove_stmt_from_eh_lp_fn): Similarly.
+       (lookup_stmt_eh_lp_fn): Rename from lookup_stmt_eh_region_fn.
+       Update for lp numbers; don't special case missing throw_stmt_table.
+       (lookup_expr_eh_lp): Similarly.
+       (lookup_stmt_eh_lp): Rename from lookup_stmt_eh_region.
+       (eh_seq, eh_region_may_contain_throw): New.
+       (struct leh_state): Add ehp_region.
+       (struct leh_tf_state): Remove eh_label.
+       (emit_post_landing_pad): New.
+       (emit_resx, emit_eh_dispatch): New.
+       (note_eh_region_may_contain_throw): New.
+       (frob_into_branch_around): Take eh_region not eh label;
+       emit eh code into eh_seq.
+       (honor_protect_cleanup_actions): Early exit for no actions.  Don't
+       handle EXC_PTR_EXPR, FILTER_EXPR.  Use gimple_build_eh_must_not_throw,
+       lower_eh_must_not_throw.  Emit code to eh_seq.
+       (lower_try_finally_nofallthru): Emit eh code to eh_seq.
+       (lower_try_finally_onedest): Likewise.
+       (lower_try_finally_copy): Likewise.
+       (lower_try_finally_switch): Likewise.
+       (lower_try_finally): Initialize ehp_region.
+       (lower_catch): Update for eh_catch objects.
+       (lower_eh_filter): Don't handle must_not_throw.
+       (lower_eh_must_not_throw): New.
+       (lower_cleanup): Don't set eh_label.
+       (lower_eh_constructs_2): Resolve eh builtins.
+       Handle GIMPLE_EH_MUST_NOT_THROW.
+       (lower_eh_constructs): Initialize eh_region_may_contain_throw.
+       Add eh_seq to the end of the function body.
+       (make_eh_dispatch_edges): New.
+       (make_eh_edge): Remove.
+       (make_eh_edges): Simplify for landing pads.
+       (redirect_eh_edge_1): New.
+       (redirect_eh_edge): Use it.
+       (redirect_eh_dispatch_edge): New.
+       (stmt_could_throw_p): Use a switch.  Allow RESX.
+       (stmt_can_throw_external): Use lookup_stmt_eh_lp.
+       (stmt_can_throw_internal): Likewise.
+       (maybe_clean_eh_stmt_fn, maybe_clean_eh_stmt): New.
+       (maybe_clean_or_replace_eh_stmt): Update for landing pads.
+       (maybe_duplicate_eh_stmt_fn, maybe_duplicate_eh_stmt): New.
+       (gate_refactor_eh): New.
+       (pass_refactor_eh): Use it.
+       (lower_resx, execute_lower_resx, pass_lower_resx): New.
+       (lower_eh_dispatch, execute_lower_eh_dispatch): New.
+       (gate_lower_ehcontrol, pass_lower_eh_dispatch): New.
+       (remove_unreachable_handlers): Rename from
+       tree_remove_unreachable_handlers; rewrite for landing pads;
+       call remove_eh_handler directly.
+       (remove_unreachable_handlers_no_lp): New.
+       (unsplit_eh, unsplit_all_eh): New.
+       (tree_empty_eh_handler_p, all_phis_safe_to_merge): Remove.
+       (cleanup_empty_eh_merge_phis, cleanup_empty_eh_move_lp): New.
+       (cleanup_empty_eh_unsplit): New.
+       (cleanup_empty_eh): Rewrite.
+       (cleanup_all_empty_eh): New.
+       (execute_cleanup_eh): Rename from cleanup_eh.  Remove unreachable
+       handlers first.  Use unsplit_all_eh, cleanup_all_empty_eh.
+       (gate_cleanup_eh): New.
+       (pass_cleanup_eh): Use it.
+       (verify_eh_edges): Move later in file.  Expect one EH edge.
+       (verify_eh_dispatch_edge): New.
+
+       * Makefile.in (FUNCTION_H): Use vecprim.h, not varray.h.
+       (gtype-desc.o): Add TARGET_H.
+       (tree.o): Use EXCEPT_H, not except.h.
+       (cfgbuild.o): Add EXPR_H.
+       (GTFILES): Add vecprim.h.
+       * builtins.c (expand_builtin): Handle BUILT_IN_EH_POINTER,
+       BUILT_IN_EH_FILTER, BUILT_IN_EH_COPY_VALUES.
+       * builtins.def (BUILT_IN_UNWIND_RESUME, BUILT_IN_EH_POINTER,
+       BUILT_IN_EH_FILTER, BUILT_IN_EH_COPY_VALUES): New.
+       * calls.c (emit_call_1): Use make_reg_eh_region_note.
+       * cfgbuild.c (control_flow_insn_p): Use can_nonlocal_goto; tidy
+       calls to can_throw_internal.
+       (rtl_make_eh_edge): Use get_eh_landing_pad_from_rtx.
+       (make_edges): Don't handle RESX; use can_nonlocal_goto.
+       * cfgexpand.c (expand_gimple_stmt_1): Don't handle RESX.
+       (expand_gimple_stmt): Use make_reg_eh_region_note.
+       (expand_debug_expr): Don't handle EXC_PTR_EXPR and FILTER_EXPR.
+       (gimple_expand_cfg): Don't call convert_from_eh_region_ranges,
+       or find_exception_handler_labels.
+       * cfgrtl.c (rtl_verify_flow_info_1): Don't handle RESX.  Assert
+       there is exacly one EH edge.  Use can_nonlocal_goto and
+       can_throw_internal.
+       * cgraphunit.c (update_call_expr): Use maybe_clean_eh_stmt_fn.
+       (cgraph_materialize_all_clones): Use maybe_clean_or_replace_eh_stmt.
+       * combine.c (can_combine_p, try_combine): Use insn_nothrow_p.
+       * cse.c (count_reg_usage, insn_live_p): Use insn_could_throw_p.
+       * dce.c (deletable_insn_p_1): Don't test may_trap_p.
+       (deletable_insn_p): Use insn_nothrow_p; reorder nonjump insn test.
+       * dse.c (scan_insn): Use insn_could_throw_p.
+       * emit-rtl.c (try_split): Use copy_reg_eh_region_note_backward.
+       * expr.c (expand_expr_real): Use make_reg_eh_region_note.
+       (expand_expr_real_1): Don't handle RESX, EXC_PTR, or FILTER_EXPR.
+       * fold-const.c (tree_expr_nonnegative_warnv_p): Don't handle
+       EXC_PTR_EXPR or FILTER_EXPR.
+       (tree_expr_nonzero_warnv_p): Likewise.
+       * function.h: Include vecprim.h, not varray.h
+       (struct rtl_eh): Remove filter, exc_ptr, built_landing_pad members;
+       move ttype_data and ehspec_data members to struct eh_status; change
+       action_record_data member to a VEC.
+       * gcse.c (hash_scan_set): Use can_throw_internal.
+       * gengtype.c (open_base_files): Add target.h to gtype-desc.c.
+       * gimple-iterator.c (gsi_replace): Use maybe_clean_or_replace_eh_stmt.
+       * gimple-low.c (lower_stmt): Handle GIMPLE_EH_MUST_NOT_THROW.
+       (block_may_fallthru): Don't handle RESX_EXPR.
+       * gimple-pretty-print.c (dump_gimple_label): Dump EH_LANDING_PAD_NR.
+       (dump_gimple_eh_must_not_throw, dump_gimple_eh_dispatch): New.
+       (dump_gimple_stmt): Dump landing pad information with TDF_EH;
+       handle GIMPLE_EH_MUST_NOT_THROW, GIMPLE_EH_DISPATCH.
+       * gimple.c (gss_for_code): Handle GIMPLE_EH_MUST_NOT_THROW,
+       GIMPLE_EH_DISPATCH, GIMPLE_RESX.
+       (gimple_size): Likewise.
+       (gimple_build_eh_dispatch, gimple_build_eh_must_not_throw): New.
+       (gimple_build_resx): Use gimple_build_with_ops.
+       (DEFTREECODE): Don't handle EXC_PTR_EXPR, FILTER_EXPR.
+       (is_gimple_val): Likewise.
+       (is_gimple_stmt): Remove RESX_EXPR.
+       * gimple.def (GIMPLE_EH_MUST_NOT_THROW, GIMPLE_EH_DISPATCH): New.
+       (GIMPLE_RESX): Reorder with other EH constructs.
+       * gimple.h (struct gimple_statement_eh_mnt): New.
+       (struct gimple_statement_eh_ctrl): Rename from gimple_statement_resx.
+       (gimple_eh_filter_must_not_throw): Remove.
+       (gimple_eh_filter_set_must_not_throw): Remove.
+       (gimple_eh_must_not_throw_fndecl): New.
+       (gimple_eh_dispatch_region, gimple_eh_dispatch_set_region): New.
+       (is_gimple_resx): New.
+       * gimplify.c (gimplify_expr): Don't handle EXC_PTR_EXPR, RESX_EXPR.
+       Don't copy EH_FILTER_MUST_NOT_THROW.
+       * gsstruct.def (GSS_EH_MNT, GSS_EHCONTROL): New.
+       * ipa-inline.c (estimate_function_body_sizes): Don't try to
+       handle must_not_throw_labels specially.
+       * ipa-pure-const.c (check_call): Update debug statement for LP.
+       * ipa-type-escape.c (check_operand): Don't handle EXC_PTR or FILTER.
+       * ipa-utils.c (get_base_var): Likewise.
+       * libfunc.h (LTI_unwind_resume, unwind_resume_libfunc): Remove.
+       * lower-subreg.c (move_eh_region_note): Remove.
+       (resolve_simple_move): Use copy_reg_eh_region_note_forward.
+       * omp-low.c (new_omp_context): Update for eh_lp_nr.
+       (create_task_copyfn): Likewise.
+       (maybe_catch_exception): Use gimple_build_eh_filter.
+       * optabs.c (emit_libcall_block): Update test for no-nonlocal-goto
+       REG_EH_REGION.  Use make_reg_eh_region_note_nothrow_nononlocal.
+       * passes.c (init_optimization_passes): Add pass_lower_eh_dispatch
+       and pass_lower_resx.
+       * print-tree.c (print_node): Dump EH_LANDING_PAD_NR.
+       * recog.c (peephole2_optimize): Use copy_reg_eh_region_note_backward,
+       can_throw_internal, can_nonlocal_goto.
+       * reload1.c (fixup_eh_region_note): Use insn_could_throw_p,
+       copy_reg_eh_region_note_forward.
+       (emit_input_reload_insns): Use copy_reg_eh_region_note_forward.
+       (emit_output_reload_insns): Likewise.
+       (copy_eh_notes): Remove.
+       * rtl.def (RESX): Remove.
+       * rtl.h: Update declarations.
+       * sese.c (graphite_copy_stmts_from_block): Use maybe_duplicate_eh_stmt.
+       * tree-cfg.c (make_edges): Handle GIMPLE_EH_DISPATCH.
+       (update_eh_label): Remove.
+       (cleanup_dead_labels_eh): New.
+       (cleanup_deal_labels): Use it instead of update_eh_label.
+       (gimple_merge_blocks): Update landing pad data structure when
+       removing a landing pad label.
+       (remove_useless_stmts_tc): Remove gimple_eh_filter_must_not_throw
+       test; handle GIMPLE_EH_MUST_NOT_THROW.
+       (is_ctrl_altering_stmt): Handle GIMPLE_EH_DISPATCH.
+       (verify_gimple_assign_single): Don't handle EXC_PTR or FILTER_EXPR.
+       (verify_types_in_gimple_stmt): Handle GIMPLE_EH_DISPATCH.
+       (verify_stmt): Likewise.  Verify landing pads.
+       (gimple_redirect_edge_and_branch): Handle GIMPLE_EH_DISPATCH.
+       (gimple_duplicate_bb): Use maybe_duplicate_eh_stmt.
+       (struct move_stmt_d): Add eh_map.
+       (move_stmt_eh_region_nr, move_stmt_eh_region_tree_nr): New.
+       (move_stmt_r): Remap eh region numbers in builtin calls,
+       resx and eh_dispatch.
+       (move_block_to_fn): Remove eh_offset parameter.  Use
+       maybe_duplicate_eh_stmt_fn.
+       (find_outermost_region_in_block): Operate on eh_region pointers
+       instead of region numbers.
+       (move_sese_region_to_fn): Expect eh_map instead of eh_offset from
+       duplicate_eh_regions.
+       * tree-cfgcleanup.c (tree_forwarder_block_p): Move entry block edge
+       test earlier.  Disallow EH landing pads.
+       * tree-cfa.c (create_tree_common_ann): Don't set ann->rn.
+       * tree-flow.h: Update declarations.
+       (struct tree_ann_common_d): Replace rn with lp_nr.
+       * tree-inline.c (copy_tree_body_r): Don't handle RESX_EXPR.
+       (remap_eh_region_nr, remap_eh_region_tree_nr): New.
+       (remap_gimple_stmt): Remap eh region numbers in builtin calls,
+       resx and eh_dispatch.
+       (copy_bb): Use maybe_duplicate_eh_stmt_fn.
+       (copy_edges_for_bb): Use make_eh_dispatch_edges.
+       (copy_cfg_body): Expect eh_map instead of eh_region_offset
+       from duplicate_eh_regions.
+       (estimate_num_insns): Don't handle EXC_PTR_EXPR or FILTER_EXPR;
+       update RESX; handle EH_DISPATCH.
+       (expand_call_inline): Set eh_lp_nr, not eh_region.
+       (maybe_inline_call_in_expr): Likewise.
+       * tree-inline.h (struct copy_body_data): Replace eh_region with
+       eh_lp_nr, eh_region_offset with eh_map.
+       * tree-optimize.c (execute_fixup_cfg): Use maybe_clean_eh_stmt.
+       * tree-pass.h (pass_lower_eh_dispatch, pass_lower_resx): New.
+       * tree-pretty-print.c (dump_generic_node): Don't handle
+       EXC_PTR_EXPR, FILTER_EXPR, RESX_EXPR.
+       * tree-sra.c (scan_function): Use maybe_clean_eh_stmt.
+       * tree-ssa-alias.c (ref_maybe_used_by_call_p_1): Don't handle
+       EXC_PTR_EXPR, FILTER_EXPR.
+       * tree-ssa-operands.c (get_expr_operands): Likewise.
+       * tree-ssa-propagate.c (valid_gimple_rhs_p): Likewise.
+       * tree-ssa-sccvn.c (copy_reference_ops_from_ref): Likewise.
+       (ao_ref_init_from_vn_reference): Likewise.
+       * tree-ssa-sink.c (statement_sink_location): Likewise.
+       * tree-ssa-dce.c (mark_stmt_if_obviously_necessary): Likewise.
+       (mark_virtual_phi_result_for_renaming): Export.  Tidy.
+       * tree-ssa-pre.c (get_or_alloc_expr_for): Don't handle
+       EXC_PTR_EXPR, FILTER_EXPR.
+       (is_exception_related): Remove.
+       (compute_avail): Don't call it.
+       * tree-ssa-structalias.c: Remove VEC definitions for int and unsigned.
+       * tree.c (find_decls_types_in_eh_region): Update for eh_region changes.
+       (find_decls_types_in_node): Use FOR_ALL_EH_REGION_FN.
+       (build_common_builtin_nodes): Add enable_cxa_end_cleanup parameter.
+       Build EH builtins.
+       (build_resx): Remove.
+       * tree.def (EXC_PTR_EXPR, FILTER_EXPR, RESX_EXPR): Remove.
+       * tree.h: Update declarations.
+       (EH_FILTER_MUST_NOT_THROW): Remove.
+       (struct tree_label_decl): Add eh_landing_pad_nr.
+       (EH_LANDING_PAD_NR): New.
+       * value-prof.c (gimple_ic): Tidy variable names.  Update for
+       landing pad numbers.
+       (gimple_stringop_fixed_value): Tidy variable names.  Assert
+       that neither call stmt can throw.
+       * vecprim.h (uchar): New.
+       (VEC(uchar,heap), VEC(uchar,gc)): New.
+
+       * c-common.c (c_define_builtins): Update call to
+       build_common_builtin_nodes.
+       * c-parser.c (c_parse_file): Don't call
+       default_init_unwind_resume_libfunc.
+
 2009-09-14  Richard Sandiford  <rdsandiford@googlemail.com>
 
        * config/mips/mips-protos.h (mips_cfun_has_cprestore_slot_p): Declare.
index d89fb2a..2e406b6 100644 (file)
@@ -856,7 +856,7 @@ RECOG_H = recog.h
 ALIAS_H = alias.h coretypes.h
 EMIT_RTL_H = emit-rtl.h
 FLAGS_H = flags.h options.h
-FUNCTION_H = function.h $(TREE_H) $(HASHTAB_H) varray.h
+FUNCTION_H = function.h $(TREE_H) $(HASHTAB_H) vecprim.h
 EXPR_H = expr.h insn-config.h $(FUNCTION_H) $(RTL_H) $(FLAGS_H) $(TREE_H) $(MACHMODE_H) $(EMIT_RTL_H)
 OPTABS_H = optabs.h insn-codes.h
 REGS_H = regs.h varray.h $(MACHMODE_H) $(OBSTACK_H) $(BASIC_BLOCK_H) $(FUNCTION_H)
@@ -2127,7 +2127,7 @@ gtype-desc.o: gtype-desc.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
        hard-reg-set.h $(BASIC_BLOCK_H) cselib.h $(INSN_ADDR_H) $(OPTABS_H) \
        libfuncs.h debug.h $(GGC_H) $(CGRAPH_H) $(TREE_FLOW_H) reload.h \
        $(CPP_ID_DATA_H) tree-chrec.h $(CFGLAYOUT_H) $(EXCEPT_H) output.h \
-       $(CFGLOOP_H)
+       $(CFGLOOP_H) $(TARGET_H)
 
 ggc-common.o: ggc-common.c $(CONFIG_H) $(SYSTEM_H) coretypes.h         \
        $(GGC_H) $(HASHTAB_H) $(TOPLEV_H) $(PARAMS_H) hosthooks.h       \
@@ -2163,10 +2163,11 @@ langhooks.o : langhooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
    intl.h $(GIMPLE_H)
 tree.o : tree.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
    all-tree.def $(FLAGS_H) $(FUNCTION_H) $(PARAMS_H) \
-   $(TOPLEV_H) $(GGC_H) $(HASHTAB_H) $(TARGET_H) output.h $(TM_P_H) langhooks.h \
-   $(REAL_H) gt-tree.h $(TREE_INLINE_H) tree-iterator.h $(BASIC_BLOCK_H) \
-   $(TREE_FLOW_H) $(OBSTACK_H) pointer-set.h fixed-value.h tree-pass.h \
-   langhooks-def.h $(DIAGNOSTIC_H) $(CGRAPH_H) $(TIMEVAR_H) except.h debug.h
+   $(TOPLEV_H) $(GGC_H) $(HASHTAB_H) $(TARGET_H) output.h $(TM_P_H) \
+   langhooks.h $(REAL_H) gt-tree.h $(TREE_INLINE_H) tree-iterator.h \
+   $(BASIC_BLOCK_H) $(TREE_FLOW_H) $(OBSTACK_H) pointer-set.h fixed-value.h \
+   tree-pass.h langhooks-def.h $(DIAGNOSTIC_H) $(CGRAPH_H) $(TIMEVAR_H) \
+   $(EXCEPT_H) debug.h
 tree-dump.o: tree-dump.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
    $(TREE_H) langhooks.h $(TOPLEV_H) $(SPLAY_TREE_H) $(TREE_DUMP_H) \
    tree-iterator.h $(TREE_PASS_H) $(DIAGNOSTIC_H) $(REAL_H) fixed-value.h
@@ -2972,7 +2973,7 @@ cfganal.o : cfganal.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
    $(TIMEVAR_H) $(OBSTACK_H) $(TOPLEV_H) vecprim.h
 cfgbuild.o : cfgbuild.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
    $(FLAGS_H) $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h output.h $(TOPLEV_H) \
-   $(FUNCTION_H) $(EXCEPT_H) $(TIMEVAR_H) $(TREE_H)
+   $(FUNCTION_H) $(EXCEPT_H) $(TIMEVAR_H) $(TREE_H) $(EXPR_H)
 cfgcleanup.o : cfgcleanup.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
    $(RTL_H) $(TIMEVAR_H) hard-reg-set.h output.h $(FLAGS_H) $(RECOG_H) \
    $(TOPLEV_H) insn-config.h cselib.h $(TARGET_H) $(TM_P_H) $(PARAMS_H) \
@@ -3460,6 +3461,7 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
   $(host_xm_file_list) \
   $(tm_file_list) $(HASHTAB_H) $(SPLAY_TREE_H) $(srcdir)/bitmap.h \
   $(srcdir)/alias.h $(srcdir)/coverage.c $(srcdir)/rtl.h \
+  $(srcdir)/vecprim.h \
   $(srcdir)/optabs.h $(srcdir)/tree.h $(srcdir)/varray.h $(srcdir)/libfuncs.h $(SYMTAB_H) \
   $(srcdir)/real.h $(srcdir)/function.h $(srcdir)/insn-addr.h $(srcdir)/hwint.h \
   $(srcdir)/fixed-value.h \
index 368d494..5747227 100644 (file)
@@ -1,3 +1,12 @@
+2009-09-14  Richard Henderson  <rth@redhat.com>
+
+       * gcc-interface/misc.c (gnat_init_gcc_eh): Don't call
+       default_init_unwind_resume_libfunc.
+       * gcc-interface/trans.c (Exception_Handler_to_gnu_zcx): Use
+       __builtin_eh_pointer.
+       * gcc-interface/utils.c (gnat_install_builtins): Update call
+       to build_common_builtin_nodes.
+
 2009-09-13  Richard Guenther  <rguenther@suse.de>
            Rafael Avila de Espindola  <espindola@google.com>
 
index 261351f..26df68d 100644 (file)
@@ -435,7 +435,6 @@ gnat_init_gcc_eh (void)
   using_eh_for_cleanups ();
 
   lang_eh_type_covers = gnat_eh_type_covers;
-  default_init_unwind_resume_libfunc ();
 
   /* Turn on -fexceptions and -fnon-call-exceptions. The first one triggers
      the generation of the necessary exception runtime tables. The second one
index 29ab72a..61a3aea 100644 (file)
@@ -3304,7 +3304,7 @@ Exception_Handler_to_gnu_zcx (Node_Id gnat_node)
      a new occurrence on top of the stack, which means that this top does not
      necessarily match the occurrence this handler was dealing with.
 
-     The EXC_PTR_EXPR object references the exception occurrence being
+     __builtin_eh_pointer references the exception occurrence being
      propagated. Upon handler entry, this is the exception for which the
      handler is triggered. This might not be the case upon handler exit,
      however, as we might have a new occurrence propagated by the handler's
@@ -3312,7 +3312,10 @@ Exception_Handler_to_gnu_zcx (Node_Id gnat_node)
 
      We use a local variable to retrieve the incoming value at handler entry
      time, and reuse it to feed the end_handler hook's argument at exit.  */
-  gnu_current_exc_ptr = build0 (EXC_PTR_EXPR, ptr_type_node);
+
+  gnu_current_exc_ptr
+    = build_call_expr (built_in_decls [BUILT_IN_EH_POINTER],
+                      1, integer_zero_node);
   gnu_incoming_exc_ptr = create_var_decl (get_identifier ("EXPTR"), NULL_TREE,
                                          ptr_type_node, gnu_current_exc_ptr,
                                          false, false, false, false, NULL,
index 9748caf..bd6a840 100644 (file)
@@ -5439,7 +5439,7 @@ gnat_install_builtins (void)
      know about internal specificities and control attributes accordingly, for
      instance __builtin_alloca vs no-throw and -fstack-check.  We will ignore
      the generic definition from builtins.def.  */
-  build_common_builtin_nodes ();
+  build_common_builtin_nodes (false);
 
   /* Now, install the target specific builtins, such as the AltiVec family on
      ppc, and the common set as exposed by builtins.def.  */
index d4801b1..ee6417d 100644 (file)
@@ -6940,6 +6940,12 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
 #endif
     case BUILT_IN_EXTEND_POINTER:
       return expand_builtin_extend_pointer (CALL_EXPR_ARG (exp, 0));
+    case BUILT_IN_EH_POINTER:
+      return expand_builtin_eh_pointer (exp);
+    case BUILT_IN_EH_FILTER:
+      return expand_builtin_eh_filter (exp);
+    case BUILT_IN_EH_COPY_VALUES:
+      return expand_builtin_eh_copy_values (exp);
 
     case BUILT_IN_VA_START:
       return expand_builtin_va_start (exp);
index 8d16936..00287c7 100644 (file)
@@ -759,6 +759,12 @@ DEF_BUILTIN (BUILT_IN_EMUTLS_REGISTER_COMMON,
             true, true, true, ATTR_NOTHROW_LIST, false,
             !targetm.have_tls)
 
+/* Exception support.  */
+DEF_BUILTIN_STUB (BUILT_IN_UNWIND_RESUME, "__builtin_unwind_resume")
+DEF_BUILTIN_STUB (BUILT_IN_EH_POINTER, "__builtin_eh_pointer")
+DEF_BUILTIN_STUB (BUILT_IN_EH_FILTER, "__builtin_eh_filter")
+DEF_BUILTIN_STUB (BUILT_IN_EH_COPY_VALUES, "__builtin_eh_copy_values")
+
 /* Synchronization Primitives.  */
 #include "sync-builtins.def"
 
index a19489c..25c0c01 100644 (file)
@@ -4574,7 +4574,7 @@ c_define_builtins (tree va_list_ref_type_node, tree va_list_arg_type_node)
 
   targetm.init_builtins ();
 
-  build_common_builtin_nodes ();
+  build_common_builtin_nodes (c_dialect_cxx ());
 
   if (flag_mudflap)
     mudflap_init ();
index ddb81e1..feec8a4 100644 (file)
@@ -8604,10 +8604,7 @@ c_parse_file (void)
 
   /* Initialize EH, if we've been told to do so.  */
   if (flag_exceptions)
-    {
-      default_init_unwind_resume_libfunc ();
-      using_eh_for_cleanups ();
-    }
+    using_eh_for_cleanups ();
 
   c_parser_translation_unit (the_parser);
   the_parser = NULL;
index 2063909..16229cc 100644 (file)
@@ -376,10 +376,8 @@ emit_call_1 (rtx funexp, tree fntree ATTRIBUTE_UNUSED, tree fndecl ATTRIBUTE_UNU
   if (ecf_flags & ECF_LOOPING_CONST_OR_PURE)
     RTL_LOOPING_CONST_OR_PURE_CALL_P (call_insn) = 1;
 
-  /* If this call can't throw, attach a REG_EH_REGION reg note to that
-     effect.  */
-  if (ecf_flags & ECF_NOTHROW)
-    add_reg_note (call_insn, REG_EH_REGION, const0_rtx);
+  /* Create a nothrow REG_EH_REGION note, if needed.  */
+  make_reg_eh_region_note (call_insn, ecf_flags, 0);
 
   if (ecf_flags & ECF_NORETURN)
     add_reg_note (call_insn, REG_NORETURN, const0_rtx);
index 6e941bf..7d87a7a 100644 (file)
@@ -33,6 +33,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "output.h"
 #include "function.h"
 #include "except.h"
+#include "expr.h"
 #include "toplev.h"
 #include "timevar.h"
 
@@ -80,8 +81,6 @@ inside_basic_block_p (const_rtx insn)
 bool
 control_flow_insn_p (const_rtx insn)
 {
-  rtx note;
-
   switch (GET_CODE (insn))
     {
     case NOTE:
@@ -101,21 +100,20 @@ control_flow_insn_p (const_rtx insn)
           || find_reg_note (insn, REG_NORETURN, 0))
          && GET_CODE (PATTERN (insn)) != COND_EXEC)
        return true;
+
       /* Call insn may return to the nonlocal goto handler.  */
-      return ((nonlocal_goto_handler_labels
-              && (0 == (note = find_reg_note (insn, REG_EH_REGION,
-                                              NULL_RTX))
-                  || INTVAL (XEXP (note, 0)) >= 0))
-             /* Or may trap.  */
-             || can_throw_internal (insn));
+      if (can_nonlocal_goto (insn))
+       return true;
+      break;
 
     case INSN:
       /* Treat trap instructions like noreturn calls (same provision).  */
       if (GET_CODE (PATTERN (insn)) == TRAP_IF
          && XEXP (PATTERN (insn), 0) == const1_rtx)
        return true;
-
-      return (flag_non_call_exceptions && can_throw_internal (insn));
+      if (!flag_non_call_exceptions)
+       return false;
+      break;
 
     case BARRIER:
       /* It is nonsense to reach barrier when looking for the
@@ -126,6 +124,8 @@ control_flow_insn_p (const_rtx insn)
     default:
       gcc_unreachable ();
     }
+
+  return can_throw_internal (insn);
 }
 
 \f
@@ -155,16 +155,23 @@ make_label_edge (sbitmap edge_cache, basic_block src, rtx label, int flags)
 void
 rtl_make_eh_edge (sbitmap edge_cache, basic_block src, rtx insn)
 {
-  int is_call = CALL_P (insn) ? EDGE_ABNORMAL_CALL : 0;
-  rtx handlers, i;
+  eh_landing_pad lp = get_eh_landing_pad_from_rtx (insn);
 
-  handlers = reachable_handlers (insn);
+  if (lp)
+    {
+      rtx label = lp->landing_pad;
 
-  for (i = handlers; i; i = XEXP (i, 1))
-    make_label_edge (edge_cache, src, XEXP (i, 0),
-                    EDGE_ABNORMAL | EDGE_EH | is_call);
+      /* During initial rtl generation, use the post_landing_pad.  */
+      if (label == NULL)
+       {
+         gcc_assert (lp->post_landing_pad);
+         label = label_rtx (lp->post_landing_pad);
+       }
 
-  free_INSN_LIST_list (&handlers);
+      make_label_edge (edge_cache, src, label,
+                      EDGE_ABNORMAL | EDGE_EH
+                      | (CALL_P (insn) ? EDGE_ABNORMAL_CALL : 0));
+    }
 }
 
 /* States of basic block as seen by find_many_sub_basic_blocks.  */
@@ -253,13 +260,9 @@ make_edges (basic_block min, basic_block max, int update_p)
        {
          rtx tmp;
 
-         /* Recognize exception handling placeholders.  */
-         if (GET_CODE (PATTERN (insn)) == RESX)
-           rtl_make_eh_edge (edge_cache, bb, insn);
-
          /* Recognize a non-local goto as a branch outside the
             current function.  */
-         else if (find_reg_note (insn, REG_NON_LOCAL_GOTO, NULL_RTX))
+         if (find_reg_note (insn, REG_NON_LOCAL_GOTO, NULL_RTX))
            ;
 
          /* Recognize a tablejump and do the right thing.  */
@@ -333,12 +336,7 @@ make_edges (basic_block min, basic_block max, int update_p)
                 gotos do not have their addresses taken, then only calls to
                 those functions or to other nested functions that use them
                 could possibly do nonlocal gotos.  */
-
-             /* We do know that a REG_EH_REGION note with a value less
-                than 0 is guaranteed not to perform a non-local goto.  */
-             rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
-
-             if (!note || INTVAL (XEXP (note, 0)) >=  0)
+             if (can_nonlocal_goto (insn))
                for (x = nonlocal_goto_handler_labels; x; x = XEXP (x, 1))
                  make_label_edge (edge_cache, bb, XEXP (x, 0),
                                   EDGE_ABNORMAL | EDGE_ABNORMAL_CALL);
@@ -446,8 +444,10 @@ find_bb_boundaries (basic_block bb)
     {
       enum rtx_code code = GET_CODE (insn);
 
-      /* On code label, split current basic block.  */
-      if (code == CODE_LABEL)
+      /* In case we've previously seen an insn that effects a control
+        flow transfer, split the block.  */
+      if ((flow_transfer_insn || code == CODE_LABEL)
+         && inside_basic_block_p (insn))
        {
          fallthru = split_block (bb, PREV_INSN (insn));
          if (flow_transfer_insn)
@@ -465,36 +465,10 @@ find_bb_boundaries (basic_block bb)
          bb = fallthru->dest;
          remove_edge (fallthru);
          flow_transfer_insn = NULL_RTX;
-         if (LABEL_ALT_ENTRY_P (insn))
+         if (code == CODE_LABEL && LABEL_ALT_ENTRY_P (insn))
            make_edge (ENTRY_BLOCK_PTR, bb, 0);
        }
 
-      /* __builtin_unreachable () may cause a barrier to be emitted in
-        the middle of a BB.  We need to split it in the same manner
-        as if the barrier were preceded by a control_flow_insn_p
-        insn.  */
-      if (code == BARRIER && !flow_transfer_insn)
-       flow_transfer_insn = prev_nonnote_insn_bb (insn);
-
-      /* In case we've previously seen an insn that effects a control
-        flow transfer, split the block.  */
-      if (flow_transfer_insn && inside_basic_block_p (insn))
-       {
-         fallthru = split_block (bb, PREV_INSN (insn));
-         BB_END (bb) = flow_transfer_insn;
-
-         /* Clean up the bb field for the insns between the blocks.  */
-         for (x = NEXT_INSN (flow_transfer_insn);
-              x != BB_HEAD (fallthru->dest);
-              x = NEXT_INSN (x))
-           if (!BARRIER_P (x))
-             set_block_for_insn (x, NULL);
-
-         bb = fallthru->dest;
-         remove_edge (fallthru);
-         flow_transfer_insn = NULL_RTX;
-       }
-
       if (control_flow_insn_p (insn))
        flow_transfer_insn = insn;
       if (insn == end)
index d1c2be2..0ed6bd5 100644 (file)
@@ -1820,9 +1820,6 @@ expand_gimple_stmt_1 (gimple stmt)
     case GIMPLE_NOP:
     case GIMPLE_PREDICT:
       break;
-    case GIMPLE_RESX:
-      expand_resx_stmt (stmt);
-      break;
     case GIMPLE_SWITCH:
       expand_case (stmt);
       break;
@@ -1961,7 +1958,7 @@ expand_gimple_stmt_1 (gimple stmt)
 static rtx
 expand_gimple_stmt (gimple stmt)
 {
-  int rn = -1;
+  int lp_nr = 0;
   rtx last = NULL;
   location_t saved_location = input_location;
 
@@ -1993,8 +1990,8 @@ expand_gimple_stmt (gimple stmt)
   input_location = saved_location;
 
   /* Mark all insns that may trap.  */
-  rn = lookup_stmt_eh_region (stmt);
-  if (rn >= 0)
+  lp_nr = lookup_stmt_eh_lp (stmt);
+  if (lp_nr)
     {
       rtx insn;
       for (insn = next_real_insn (last); insn;
@@ -2005,9 +2002,8 @@ expand_gimple_stmt (gimple stmt)
                 may_trap_p instruction may throw.  */
              && GET_CODE (PATTERN (insn)) != CLOBBER
              && GET_CODE (PATTERN (insn)) != USE
-             && (CALL_P (insn)
-                 || (flag_non_call_exceptions && may_trap_p (PATTERN (insn)))))
-           add_reg_note (insn, REG_EH_REGION, GEN_INT (rn));
+             && insn_could_throw_p (insn))
+           make_reg_eh_region_note (insn, 0, lp_nr);
        }
     }
 
@@ -2540,15 +2536,6 @@ expand_debug_expr (tree exp)
                                     op0, GEN_INT (bitsize), GEN_INT (bitpos));
       }
 
-    case EXC_PTR_EXPR:
-      /* ??? Do not call get_exception_pointer(), we don't want to gen
-        it if it hasn't been created yet.  */
-      return get_exception_pointer ();
-
-    case FILTER_EXPR:
-      /* Likewise get_exception_filter().  */
-      return get_exception_filter ();
-
     case ABS_EXPR:
       return gen_rtx_ABS (mode, op0);
 
@@ -3556,12 +3543,10 @@ gimple_expand_cfg (void)
   set_curr_insn_block (DECL_INITIAL (current_function_decl));
   insn_locators_finalize ();
 
-  /* Convert tree EH labels to RTL EH labels and zap the tree EH table.  */
-  convert_from_eh_region_ranges ();
+  /* Zap the tree EH table.  */
   set_eh_throw_stmt_table (cfun, NULL);
 
   rebuild_jump_labels (get_insns ());
-  find_exception_handler_labels ();
 
   FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb)
     {
index 4c4b3b7..a7e93dd 100644 (file)
@@ -1873,12 +1873,16 @@ rtl_verify_flow_info_1 (void)
            n_abnormal++;
        }
 
-      if (n_eh && GET_CODE (PATTERN (BB_END (bb))) != RESX
-         && !find_reg_note (BB_END (bb), REG_EH_REGION, NULL_RTX))
+      if (n_eh && !find_reg_note (BB_END (bb), REG_EH_REGION, NULL_RTX))
        {
          error ("missing REG_EH_REGION note in the end of bb %i", bb->index);
          err = 1;
        }
+      if (n_eh > 1)
+       {
+         error ("too many eh edges %i", bb->index);
+         err = 1;
+       }
       if (n_branch
          && (!JUMP_P (BB_END (bb))
              || (n_branch > 1 && (any_uncondjump_p (BB_END (bb))
@@ -1894,7 +1898,8 @@ rtl_verify_flow_info_1 (void)
        }
       if (n_branch != 1 && any_uncondjump_p (BB_END (bb)))
        {
-         error ("wrong amount of branch edges after unconditional jump %i", bb->index);
+         error ("wrong number of branch edges after unconditional jump %i",
+                bb->index);
          err = 1;
        }
       if (n_branch != 1 && any_condjump_p (BB_END (bb))
@@ -2217,39 +2222,33 @@ purge_dead_edges (basic_block bb)
   /* Cleanup abnormal edges caused by exceptions or non-local gotos.  */
   for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); )
     {
+      bool remove = false;
+
       /* There are three types of edges we need to handle correctly here: EH
         edges, abnormal call EH edges, and abnormal call non-EH edges.  The
         latter can appear when nonlocal gotos are used.  */
-      if (e->flags & EDGE_EH)
+      if (e->flags & EDGE_ABNORMAL_CALL)
        {
-         if (can_throw_internal (insn)
-             /* If this is a call edge, verify that this is a call insn.  */
-             && (! (e->flags & EDGE_ABNORMAL_CALL)
-                 || CALL_P (insn)))
-           {
-             ei_next (&ei);
-             continue;
-           }
+         if (!CALL_P (insn))
+           remove = true;
+         else if (can_nonlocal_goto (insn))
+           ;
+         else if ((e->flags & EDGE_EH) && can_throw_internal (insn))
+           ;
+         else
+           remove = true;
        }
-      else if (e->flags & EDGE_ABNORMAL_CALL)
+      else if (e->flags & EDGE_EH)
+       remove = !can_throw_internal (insn);
+
+      if (remove)
        {
-         if (CALL_P (insn)
-             && (! (note = find_reg_note (insn, REG_EH_REGION, NULL))
-                 || INTVAL (XEXP (note, 0)) >= 0))
-           {
-             ei_next (&ei);
-             continue;
-           }
+         remove_edge (e);
+         df_set_bb_dirty (bb);
+         purged = true;
        }
       else
-       {
-         ei_next (&ei);
-         continue;
-       }
-
-      remove_edge (e);
-      df_set_bb_dirty (bb);
-      purged = true;
+       ei_next (&ei);
     }
 
   if (JUMP_P (insn))
index 5551c72..2ad0718 100644 (file)
@@ -1561,10 +1561,7 @@ update_call_expr (struct cgraph_node *new_version)
     {
       struct function *inner_function = DECL_STRUCT_FUNCTION (e->caller->decl);
       gimple_call_set_fndecl (e->call_stmt, new_version->decl);
-      /* Update EH information too, just in case.  */
-      if (!stmt_could_throw_p (e->call_stmt)
-          && lookup_stmt_eh_region_fn (inner_function, e->call_stmt))
-        remove_stmt_from_eh_region_fn (inner_function, e->call_stmt);
+      maybe_clean_eh_stmt_fn (inner_function, e->call_stmt);
     }
 }
 
@@ -1909,9 +1906,7 @@ cgraph_materialize_all_clones (void)
                gsi_replace (&gsi, new_stmt, true);
 
                /* Update EH information too, just in case.  */
-               if (!stmt_could_throw_p (new_stmt)
-                   && lookup_stmt_eh_region (new_stmt))
-                 remove_stmt_from_eh_region (new_stmt);
+               maybe_clean_or_replace_eh_stmt (e->call_stmt, new_stmt);
 
                cgraph_set_call_stmt_including_clones (node, e->call_stmt, new_stmt);
 
index 3437216..6b507c2 100644 (file)
@@ -1562,7 +1562,6 @@ can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED, rtx succ,
       for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
        {
          rtx elt = XVECEXP (PATTERN (insn), 0, i);
-         rtx note;
 
          switch (GET_CODE (elt))
            {
@@ -1613,9 +1612,8 @@ can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED, rtx succ,
              /* Ignore SETs whose result isn't used but not those that
                 have side-effects.  */
              if (find_reg_note (insn, REG_UNUSED, SET_DEST (elt))
-                 && (!(note = find_reg_note (insn, REG_EH_REGION, NULL_RTX))
-                     || INTVAL (XEXP (note, 0)) <= 0)
-                 && ! side_effects_p (elt))
+                 && insn_nothrow_p (insn)
+                 && !side_effects_p (elt))
                break;
 
              /* If we have already found a SET, this is a second one and
@@ -3108,15 +3106,13 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
     {
       rtx set0 = XVECEXP (newpat, 0, 0);
       rtx set1 = XVECEXP (newpat, 0, 1);
-      rtx note;
 
       if (((REG_P (SET_DEST (set1))
            && find_reg_note (i3, REG_UNUSED, SET_DEST (set1)))
           || (GET_CODE (SET_DEST (set1)) == SUBREG
               && find_reg_note (i3, REG_UNUSED, SUBREG_REG (SET_DEST (set1)))))
-         && (!(note = find_reg_note (i3, REG_EH_REGION, NULL_RTX))
-             || INTVAL (XEXP (note, 0)) <= 0)
-         && ! side_effects_p (SET_SRC (set1)))
+         && insn_nothrow_p (i3)
+         && !side_effects_p (SET_SRC (set1)))
        {
          newpat = set0;
          insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
@@ -3127,9 +3123,8 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
                || (GET_CODE (SET_DEST (set0)) == SUBREG
                    && find_reg_note (i3, REG_UNUSED,
                                      SUBREG_REG (SET_DEST (set0)))))
-              && (!(note = find_reg_note (i3, REG_EH_REGION, NULL_RTX))
-                  || INTVAL (XEXP (note, 0)) <= 0)
-              && ! side_effects_p (SET_SRC (set0)))
+              && insn_nothrow_p (i3)
+              && !side_effects_p (SET_SRC (set0)))
        {
          newpat = set1;
          insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
index a50e9fc..4a17a77 100644 (file)
@@ -1,3 +1,11 @@
+2009-09-14  Richard Henderson  <rth@redhat.com>
+
+       * except.c (init_exception_processing): Don't call
+       default_init_unwind_resume_libfunc.
+       (cp_protect_cleanup_actions): Return the decl to call.
+       (build_exc_ptr): Use __builtin_eh_pointer.
+       * optimize.c (clone_body): Set eh_lp_nr, not eh_region.
+
 2009-09-13  Richard Guenther  <rguenther@suse.de>
        Rafael Avila de Espindola  <espindola@google.com>
 
index 588c2ee..1b13819 100644 (file)
@@ -53,7 +53,7 @@ static tree wrap_cleanups_r (tree *, int *, void *);
 static int complete_ptr_ref_or_void_ptr_p (tree, tree);
 static bool is_admissible_throw_operand (tree);
 static int can_convert_eh (tree, tree);
-static gimple cp_protect_cleanup_actions (void);
+static tree cp_protect_cleanup_actions (void);
 
 /* Sets up all the global eh stuff that needs to be initialized at the
    start of compilation.  */
@@ -77,25 +77,20 @@ init_exception_processing (void)
   call_unexpected_node
     = push_throw_library_fn (get_identifier ("__cxa_call_unexpected"), tmp);
 
-  if (targetm.arm_eabi_unwinder)
-    unwind_resume_libfunc = init_one_libfunc ("__cxa_end_cleanup");
-  else
-    default_init_unwind_resume_libfunc ();
-
   lang_protect_cleanup_actions = &cp_protect_cleanup_actions;
 }
 
 /* Returns an expression to be executed if an unhandled exception is
    propagated out of a cleanup region.  */
 
-static gimple
+static tree
 cp_protect_cleanup_actions (void)
 {
   /* [except.terminate]
 
      When the destruction of an object during stack unwinding exits
      using an exception ... void terminate(); is called.  */
-  return gimple_build_call (terminate_node, 0);
+  return terminate_node;
 }
 
 static tree
@@ -154,7 +149,8 @@ build_eh_type_type (tree type)
 tree
 build_exc_ptr (void)
 {
-  return build0 (EXC_PTR_EXPR, ptr_type_node);
+  return build_call_n (built_in_decls [BUILT_IN_EH_POINTER],
+                      1, integer_zero_node);
 }
 
 /* Declare a function NAME, returning RETURN_TYPE, taking a single
index abd38f8..58d5b90 100644 (file)
@@ -99,7 +99,7 @@ clone_body (tree clone, tree fn, void *arg_map)
   id.transform_lang_insert_block = NULL;
 
   /* We're not inside any EH region.  */
-  id.eh_region = -1;
+  id.eh_lp_nr = 0;
 
   stmts = DECL_SAVED_TREE (fn);
   walk_tree (&stmts, copy_tree_body_r, &id, NULL);
index 3f3b863..8f49a9a 100644 (file)
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -6544,9 +6544,9 @@ count_reg_usage (rtx x, int *counts, rtx dest, int incr)
     case CALL_INSN:
     case INSN:
     case JUMP_INSN:
-    /* We expect dest to be NULL_RTX here.  If the insn may trap, mark
-       this fact by setting DEST to pc_rtx.  */
-      if (flag_non_call_exceptions && may_trap_p (PATTERN (x)))
+      /* We expect dest to be NULL_RTX here.  If the insn may trap, mark
+         this fact by setting DEST to pc_rtx.  */
+      if (insn_could_throw_p (x))
        dest = pc_rtx;
       if (code == CALL_INSN)
        count_reg_usage (CALL_INSN_FUNCTION_USAGE (x), counts, dest, incr);
@@ -6658,7 +6658,7 @@ static bool
 insn_live_p (rtx insn, int *counts)
 {
   int i;
-  if (flag_non_call_exceptions && may_trap_p (PATTERN (insn)))
+  if (insn_could_throw_p (insn))
     return true;
   else if (GET_CODE (PATTERN (insn)) == SET)
     return set_live_p (PATTERN (insn), insn, counts);
index 3e1dd47..b937dd4 100644 (file)
--- a/gcc/dce.c
+++ b/gcc/dce.c
@@ -79,13 +79,7 @@ deletable_insn_p_1 (rtx body)
       return false;
 
     default:
-      if (volatile_refs_p (body))
-       return false;
-
-      if (flag_non_call_exceptions && may_trap_p (body))
-       return false;
-
-      return true;
+      return !volatile_refs_p (body);
     }
 }
 
@@ -99,6 +93,14 @@ deletable_insn_p (rtx insn, bool fast, bitmap arg_stores)
   rtx body, x;
   int i;
 
+  /* Don't delete jumps, notes and the like.  */
+  if (!NONJUMP_INSN_P (insn))
+    return false;
+
+  /* Don't delete insns that can throw.  */
+  if (!insn_nothrow_p (insn))
+    return false;
+
   if (CALL_P (insn)
       /* We cannot delete calls inside of the recursive dce because
         this may cause basic blocks to be deleted and this messes up
@@ -113,13 +115,6 @@ deletable_insn_p (rtx insn, bool fast, bitmap arg_stores)
          && !RTL_LOOPING_CONST_OR_PURE_CALL_P (insn)))
     return find_call_stack_args (insn, false, fast, arg_stores);
 
-  if (!NONJUMP_INSN_P (insn))
-    return false;
-
-  /* Similarly, we cannot delete other insns that can throw either.  */
-  if (df_in_progress && flag_non_call_exceptions && can_throw_internal (insn))
-    return false;
-
   body = PATTERN (insn);
   switch (GET_CODE (body))
     {
index 3e6b57d..9d3e2c0 100644 (file)
--- a/gcc/dse.c
+++ b/gcc/dse.c
@@ -2531,7 +2531,7 @@ scan_insn (bb_info_t bb_info, rtx insn)
      them.  */
   if ((GET_CODE (PATTERN (insn)) == CLOBBER)
       || volatile_refs_p (PATTERN (insn))
-      || (flag_non_call_exceptions && may_trap_p (PATTERN (insn)))
+      || insn_could_throw_p (insn)
       || (RTX_FRAME_RELATED_P (insn))
       || find_reg_note (insn, REG_FRAME_RELATED_EXPR, NULL_RTX))
     insn_info->cannot_delete = true;
index 65022fc..9ed36b3 100644 (file)
@@ -3492,13 +3492,7 @@ try_split (rtx pat, rtx trial, int last)
       switch (REG_NOTE_KIND (note))
        {
        case REG_EH_REGION:
-         for (insn = insn_last; insn != NULL_RTX; insn = PREV_INSN (insn))
-           {
-             if (CALL_P (insn)
-                 || (flag_non_call_exceptions && INSN_P (insn)
-                     && may_trap_p (PATTERN (insn))))
-               add_reg_note (insn, REG_EH_REGION, XEXP (note, 0));
-           }
+         copy_reg_eh_region_note_backward (note, insn_last, NULL);
          break;
 
        case REG_NORETURN:
index 9b6c24e..c916a18 100644 (file)
@@ -21,30 +21,94 @@ along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
 
-/* An exception is an event that can be signaled from within a
-   function. This event can then be "caught" or "trapped" by the
-   callers of this function. This potentially allows program flow to
-   be transferred to any arbitrary code associated with a function call
-   several levels up the stack.
-
-   The intended use for this mechanism is for signaling "exceptional
-   events" in an out-of-band fashion, hence its name. The C++ language
-   (and many other OO-styled or functional languages) practically
-   requires such a mechanism, as otherwise it becomes very difficult
-   or even impossible to signal failure conditions in complex
-   situations.  The traditional C++ example is when an error occurs in
-   the process of constructing an object; without such a mechanism, it
-   is impossible to signal that the error occurs without adding global
-   state variables and error checks around every object construction.
-
-   The act of causing this event to occur is referred to as "throwing
-   an exception". (Alternate terms include "raising an exception" or
-   "signaling an exception".) The term "throw" is used because control
-   is returned to the callers of the function that is signaling the
-   exception, and thus there is the concept of "throwing" the
-   exception up the call stack.
-
-   [ Add updated documentation on how to use this.  ]  */
+/* An exception is an event that can be "thrown" from within a
+   function.  This event can then be "caught" by the callers of
+   the function.
+
+   The representation of exceptions changes several times during
+   the compilation process:
+
+   In the beginning, in the front end, we have the GENERIC trees
+   TRY_CATCH_EXPR, TRY_FINALLY_EXPR, WITH_CLEANUP_EXPR,
+   CLEANUP_POINT_EXPR, CATCH_EXPR, and EH_FILTER_EXPR.
+
+   During initial gimplification (gimplify.c) these are lowered
+   to the GIMPLE_TRY, GIMPLE_CATCH, and GIMPLE_EH_FILTER nodes.
+   The WITH_CLEANUP_EXPR and CLEANUP_POINT_EXPR nodes are converted
+   into GIMPLE_TRY_FINALLY nodes; the others are a more direct 1-1
+   conversion.
+
+   During pass_lower_eh (tree-eh.c) we record the nested structure
+   of the TRY nodes in EH_REGION nodes in CFUN->EH->REGION_TREE.
+   We expand the lang_protect_cleanup_actions hook into MUST_NOT_THROW
+   regions at this time.  We can then flatten the statements within
+   the TRY nodes to straight-line code.  Statements that had been within
+   TRY nodes that can throw are recorded within CFUN->EH->THROW_STMT_TABLE,
+   so that we may remember what action is supposed to be taken if
+   a given statement does throw.  During this lowering process,
+   we create an EH_LANDING_PAD node for each EH_REGION that has
+   some code within the function that needs to be executed if a
+   throw does happen.  We also create RESX statements that are 
+   used to transfer control from an inner EH_REGION to an outer
+   EH_REGION.  We also create EH_DISPATCH statements as placeholders
+   for a runtime type comparison that should be made in order to
+   select the action to perform among different CATCH and EH_FILTER
+   regions.
+
+   During pass_lower_eh_dispatch (tree-eh.c), which is run after
+   all inlining is complete, we are able to run assign_filter_values,
+   which allows us to map the set of types manipulated by all of the
+   CATCH and EH_FILTER regions to a set of integers.  This set of integers
+   will be how the exception runtime communicates with the code generated
+   within the function.  We then expand the GIMPLE_EH_DISPATCH statements
+   to a switch or conditional branches that use the argument provided by
+   the runtime (__builtin_eh_filter) and the set of integers we computed
+   in assign_filter_values.
+
+   During pass_lower_resx (tree-eh.c), which is run near the end
+   of optimization, we expand RESX statements.  If the eh region
+   that is outer to the RESX statement is a MUST_NOT_THROW, then
+   the RESX expands to some form of abort statement.  If the eh
+   region that is outer to the RESX statement is within the current
+   function, then the RESX expands to a bookkeeping call
+   (__builtin_eh_copy_values) and a goto.  Otherwise, the next
+   handler for the exception must be within a function somewhere
+   up the call chain, so we call back into the exception runtime
+   (__builtin_unwind_resume).
+   
+   During pass_expand (cfgexpand.c), we generate REG_EH_REGION notes
+   that create an rtl to eh_region mapping that corresponds to the
+   gimple to eh_region mapping that had been recorded in the
+   THROW_STMT_TABLE.
+
+   During pass_rtl_eh (except.c), we generate the real landing pads
+   to which the runtime will actually transfer control.  These new
+   landing pads perform whatever bookkeeping is needed by the target
+   backend in order to resume execution within the current function.
+   Each of these new landing pads falls through into the post_landing_pad
+   label which had been used within the CFG up to this point.  All
+   exception edges within the CFG are redirected to the new landing pads.
+   If the target uses setjmp to implement exceptions, the various extra
+   calls into the runtime to register and unregister the current stack
+   frame are emitted at this time.
+
+   During pass_convert_to_eh_region_ranges (except.c), we transform
+   the REG_EH_REGION notes attached to individual insns into 
+   non-overlapping ranges of insns bounded by NOTE_INSN_EH_REGION_BEG
+   and NOTE_INSN_EH_REGION_END.  Each insn within such ranges has the
+   same associated action within the exception region tree, meaning
+   that (1) the exception is caught by the same landing pad within the
+   current function, (2) the exception is blocked by the runtime with
+   a MUST_NOT_THROW region, or (3) the exception is not handled at all
+   within the current function.
+
+   Finally, during assembly generation, we call
+   output_function_exception_table (except.c) to emit the tables with
+   which the exception runtime can determine if a given stack frame
+   handles a given exception, and if so what filter value to provide
+   to the function when the non-local control transfer is effected.
+   If the target uses dwarf2 unwinding to implement exceptions, then
+   output_call_frame_info (dwarf2out.c) emits the required unwind data.  */
 
 
 #include "config.h"
@@ -87,18 +151,11 @@ along with GCC; see the file COPYING3.  If not see
 
 /* Protect cleanup actions with must-not-throw regions, with a call
    to the given failure handler.  */
-gimple (*lang_protect_cleanup_actions) (void);
+tree (*lang_protect_cleanup_actions) (void);
 
 /* Return true if type A catches type B.  */
 int (*lang_eh_type_covers) (tree a, tree b);
 
-/* A hash table of label to region number.  */
-
-struct GTY(()) ehl_map_entry {
-  rtx label;
-  struct eh_region_d *region;
-};
-
 static GTY(()) int call_site_base;
 static GTY ((param_is (union tree_node)))
   htab_t type_to_runtime_map;
@@ -118,6 +175,9 @@ struct GTY(()) call_site_record_d
   int action;
 };
 \f
+static bool get_eh_region_and_lp_from_rtx (const_rtx, eh_region *,
+                                          eh_landing_pad *);
+
 static int t2r_eq (const void *, const void *);
 static hashval_t t2r_hash (const void *);
 
@@ -127,49 +187,16 @@ static int ehspec_filter_eq (const void *, const void *);
 static hashval_t ehspec_filter_hash (const void *);
 static int add_ttypes_entry (htab_t, tree);
 static int add_ehspec_entry (htab_t, htab_t, tree);
-static void assign_filter_values (void);
-static void build_post_landing_pads (void);
-static void connect_post_landing_pads (void);
 static void dw2_build_landing_pads (void);
 
-struct sjlj_lp_info;
-static bool sjlj_find_directly_reachable_regions (struct sjlj_lp_info *);
-static void sjlj_assign_call_site_values (rtx, struct sjlj_lp_info *);
-static void sjlj_mark_call_sites (struct sjlj_lp_info *);
-static void sjlj_emit_function_enter (rtx);
-static void sjlj_emit_function_exit (void);
-static void sjlj_emit_dispatch_table (rtx, struct sjlj_lp_info *);
-static void sjlj_build_landing_pads (void);
-
-static void remove_eh_handler (struct eh_region_d *);
-static void remove_eh_handler_and_replace (struct eh_region_d *,
-                                          struct eh_region_d *, bool);
-
-/* The return value of reachable_next_level.  */
-enum reachable_code
-{
-  /* The given exception is not processed by the given region.  */
-  RNL_NOT_CAUGHT,
-  /* The given exception may need processing by the given region.  */
-  RNL_MAYBE_CAUGHT,
-  /* The given exception is completely processed by the given region.  */
-  RNL_CAUGHT,
-  /* The given exception is completely processed by the runtime.  */
-  RNL_BLOCKED
-};
-
-struct reachable_info;
-static enum reachable_code reachable_next_level (struct eh_region_d *, tree,
-                                                struct reachable_info *, bool);
-
 static int action_record_eq (const void *, const void *);
 static hashval_t action_record_hash (const void *);
 static int add_action_record (htab_t, int, int);
-static int collect_one_action_chain (htab_t, struct eh_region_d *);
+static int collect_one_action_chain (htab_t, eh_region);
 static int add_call_site (rtx, int, int);
 
-static void push_uleb128 (varray_type *, unsigned int);
-static void push_sleb128 (varray_type *, int);
+static void push_uleb128 (VEC (uchar, gc) **, unsigned int);
+static void push_sleb128 (VEC (uchar, gc) **, int);
 #ifndef HAVE_AS_LEB128
 static int dw2_size_of_call_site_table (int);
 static int sjlj_size_of_call_site_table (void);
@@ -305,16 +332,20 @@ void
 init_eh_for_function (void)
 {
   cfun->eh = GGC_CNEW (struct eh_status);
+
+  /* Make sure zero'th entries are used.  */
+  VEC_safe_push (eh_region, gc, cfun->eh->region_array, NULL);
+  VEC_safe_push (eh_landing_pad, gc, cfun->eh->lp_array, NULL);
 }
 \f
 /* Routines to generate the exception tree somewhat directly.
    These are used from tree-eh.c when processing exception related
    nodes during tree optimization.  */
 
-static struct eh_region_d *
-gen_eh_region (enum eh_region_type type, struct eh_region_d *outer)
+static eh_region
+gen_eh_region (enum eh_region_type type, eh_region outer)
 {
-  struct eh_region_d *new_eh;
+  eh_region new_eh;
 
 #ifdef ENABLE_CHECKING
   gcc_assert (doing_eh (0));
@@ -335,30 +366,32 @@ gen_eh_region (enum eh_region_type type, struct eh_region_d *outer)
       cfun->eh->region_tree = new_eh;
     }
 
-  new_eh->region_number = ++cfun->eh->last_region_number;
+  new_eh->index = VEC_length (eh_region, cfun->eh->region_array);
+  VEC_safe_push (eh_region, gc, cfun->eh->region_array, new_eh);
 
   return new_eh;
 }
 
-struct eh_region_d *
-gen_eh_region_cleanup (struct eh_region_d *outer)
+eh_region
+gen_eh_region_cleanup (eh_region outer)
 {
-  struct eh_region_d *cleanup = gen_eh_region (ERT_CLEANUP, outer);
-  return cleanup;
+  return gen_eh_region (ERT_CLEANUP, outer);
 }
 
-struct eh_region_d *
-gen_eh_region_try (struct eh_region_d *outer)
+eh_region
+gen_eh_region_try (eh_region outer)
 {
   return gen_eh_region (ERT_TRY, outer);
 }
 
-struct eh_region_d *
-gen_eh_region_catch (struct eh_region_d *t, tree type_or_list)
+eh_catch
+gen_eh_region_catch (eh_region t, tree type_or_list)
 {
-  struct eh_region_d *c, *l;
+  eh_catch c, l;
   tree type_list, type_node;
 
+  gcc_assert (t->type == ERT_TRY);
+
   /* Ensure to always end up with a type list to normalize further
      processing, then register each type against the runtime types map.  */
   type_list = type_or_list;
@@ -372,23 +405,23 @@ gen_eh_region_catch (struct eh_region_d *t, tree type_or_list)
        add_type_for_runtime (TREE_VALUE (type_node));
     }
 
-  c = gen_eh_region (ERT_CATCH, t->outer);
-  c->u.eh_catch.type_list = type_list;
+  c = GGC_CNEW (struct eh_catch_d);
+  c->type_list = type_list;
   l = t->u.eh_try.last_catch;
-  c->u.eh_catch.prev_catch = l;
+  c->prev_catch = l;
   if (l)
-    l->u.eh_catch.next_catch = c;
+    l->next_catch = c;
   else
-    t->u.eh_try.eh_catch = c;
+    t->u.eh_try.first_catch = c;
   t->u.eh_try.last_catch = c;
 
   return c;
 }
 
-struct eh_region_d *
-gen_eh_region_allowed (struct eh_region_d *outer, tree allowed)
+eh_region
+gen_eh_region_allowed (eh_region outer, tree allowed)
 {
-  struct eh_region_d *region = gen_eh_region (ERT_ALLOWED_EXCEPTIONS, outer);
+  eh_region region = gen_eh_region (ERT_ALLOWED_EXCEPTIONS, outer);
   region->u.allowed.type_list = allowed;
 
   for (; allowed ; allowed = TREE_CHAIN (allowed))
@@ -397,1340 +430,295 @@ gen_eh_region_allowed (struct eh_region_d *outer, tree allowed)
   return region;
 }
 
-struct eh_region_d *
-gen_eh_region_must_not_throw (struct eh_region_d *outer)
+eh_region
+gen_eh_region_must_not_throw (eh_region outer)
 {
   return gen_eh_region (ERT_MUST_NOT_THROW, outer);
 }
 
-int
-get_eh_region_number (struct eh_region_d *region)
+eh_landing_pad
+gen_eh_landing_pad (eh_region region)
 {
-  return region->region_number;
-}
+  eh_landing_pad lp = GGC_CNEW (struct eh_landing_pad_d);
 
-bool
-get_eh_region_may_contain_throw (struct eh_region_d *region)
-{
-  return region->may_contain_throw;
+  lp->next_lp = region->landing_pads;
+  lp->region = region;
+  lp->index = VEC_length (eh_landing_pad, cfun->eh->lp_array);
+  region->landing_pads = lp;
+
+  VEC_safe_push (eh_landing_pad, gc, cfun->eh->lp_array, lp);
+
+  return lp;
 }
 
-tree
-get_eh_region_tree_label (struct eh_region_d *region)
+eh_region
+get_eh_region_from_number_fn (struct function *ifun, int i)
 {
-  return region->tree_label;
+  return VEC_index (eh_region, ifun->eh->region_array, i);
 }
 
-tree
-get_eh_region_no_tree_label (int region)
+eh_region
+get_eh_region_from_number (int i)
 {
-  return VEC_index (eh_region, cfun->eh->region_array, region)->tree_label;
+  return get_eh_region_from_number_fn (cfun, i);
 }
 
-void
-set_eh_region_tree_label (struct eh_region_d *region, tree lab)
+eh_landing_pad
+get_eh_landing_pad_from_number_fn (struct function *ifun, int i)
 {
-  region->tree_label = lab;
+  return VEC_index (eh_landing_pad, ifun->eh->lp_array, i);
 }
-\f
-void
-expand_resx_stmt (gimple stmt)
-{
-  int region_nr = gimple_resx_region (stmt);
-  rtx insn;
-  struct eh_region_d *reg = VEC_index (eh_region,
-                                      cfun->eh->region_array, region_nr);
 
-  do_pending_stack_adjust ();
-  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 ();
+eh_landing_pad
+get_eh_landing_pad_from_number (int i)
+{
+  return get_eh_landing_pad_from_number_fn (cfun, i);
 }
 
-/* Note that the current EH region (if any) may contain a throw, or a
-   call to a function which itself may contain a throw.  */
-
-void
-note_eh_region_may_contain_throw (struct eh_region_d *region)
+eh_region
+get_eh_region_from_lp_number_fn (struct function *ifun, int i)
 {
-  while (region && !region->may_contain_throw)
+  if (i < 0)
+    return VEC_index (eh_region, ifun->eh->region_array, -i);
+  else if (i == 0)
+    return NULL;
+  else
     {
-      region->may_contain_throw = 1;
-      region = region->outer;
+      eh_landing_pad lp;
+      lp = VEC_index (eh_landing_pad, ifun->eh->lp_array, i);
+      return lp->region;
     }
 }
 
-
-/* Return an rtl expression for a pointer to the exception object
-   within a handler.  */
-
-rtx
-get_exception_pointer (void)
+eh_region
+get_eh_region_from_lp_number (int i)
 {
-  if (! crtl->eh.exc_ptr)
-    crtl->eh.exc_ptr = gen_reg_rtx (ptr_mode);
-  return crtl->eh.exc_ptr;
+  return get_eh_region_from_lp_number_fn (cfun, i);
 }
+\f
+/* Returns true if the current function has exception handling regions.  */
 
-/* Return an rtl expression for the exception dispatch filter
-   within a handler.  */
-
-rtx
-get_exception_filter (void)
+bool
+current_function_has_exception_handlers (void)
 {
-  if (! crtl->eh.filter)
-    crtl->eh.filter = gen_reg_rtx (targetm.eh_return_filter_mode ());
-  return crtl->eh.filter;
+  return cfun->eh->region_tree != NULL;
 }
 \f
-/* This section is for the exception handling specific optimization pass.  */
-
-/* Random access the exception region tree.  */
+/* A subroutine of duplicate_eh_regions.  Copy the eh_region tree at OLD.
+   Root it at OUTER, and apply LP_OFFSET to the lp numbers.  */
 
-void
-collect_eh_region_array (void)
+struct duplicate_eh_regions_data
 {
-  struct eh_region_d *i;
+  duplicate_eh_regions_map label_map;
+  void *label_map_data;
+  struct pointer_map_t *eh_map;
+};
 
-  i = cfun->eh->region_tree;
-  if (! i)
-    return;
+static void
+duplicate_eh_regions_1 (struct duplicate_eh_regions_data *data,
+                       eh_region old_r, eh_region outer)
+{
+  eh_landing_pad old_lp, new_lp;
+  eh_region new_r;
+  void **slot;
 
-  VEC_safe_grow (eh_region, gc, cfun->eh->region_array,
-                cfun->eh->last_region_number + 1);
-  VEC_replace (eh_region, cfun->eh->region_array, 0, 0);
+  new_r = gen_eh_region (old_r->type, outer);
+  slot = pointer_map_insert (data->eh_map, (void *)old_r);
+  gcc_assert (*slot == NULL);
+  *slot = (void *)new_r;
 
-  while (1)
+  switch (old_r->type)
     {
-      VEC_replace (eh_region, cfun->eh->region_array, i->region_number, i);
+    case ERT_CLEANUP:
+      break;
 
-      /* If there are sub-regions, process them.  */
-      if (i->inner)
-       i = i->inner;
-      /* If there are peers, process them.  */
-      else if (i->next_peer)
-       i = i->next_peer;
-      /* Otherwise, step back up the tree to the next peer.  */
-      else
-       {
-         do {
-           i = i->outer;
-           if (i == NULL)
-             return;
-         } while (i->next_peer == NULL);
-         i = i->next_peer;
-       }
-    }
-}
+    case ERT_TRY:
+      {
+       eh_catch oc, nc;
+       for (oc = old_r->u.eh_try.first_catch; oc ; oc = oc->next_catch)
+         {
+           /* We should be doing all our region duplication before and
+              during inlining, which is before filter lists are created.  */
+           gcc_assert (oc->filter_list == NULL);
+           nc = gen_eh_region_catch (new_r, oc->type_list);
+           nc->label = data->label_map (oc->label, data->label_map_data);
+         }
+      }
+      break;
 
-/* R is MUST_NOT_THROW region that is not reachable via local
-   RESX instructions.  It still must be kept in the tree in case runtime
-   can unwind through it, or we will eliminate out terminate call
-   runtime would do otherwise.  Return TRUE if R contains throwing statements
-   or some of the exceptions in inner regions can be unwound up to R. 
-   
-   CONTAINS_STMT is bitmap of all regions that contains some throwing
-   statements.  
-   
-   Function looks O(^3) at first sight.  In fact the function is called at most
-   once for every MUST_NOT_THROW in EH tree from remove_unreachable_regions
-   Because the outer loop walking subregions does not dive in MUST_NOT_THROW,
-   the outer loop examines every region at most once.  The inner loop
-   is doing unwinding from the throwing statement same way as we do during
-   CFG construction, so it is O(^2) in size of EH tree, but O(n) in size
-   of CFG.  In practice Eh trees are wide, not deep, so this is not
-   a problem.  */
+    case ERT_ALLOWED_EXCEPTIONS:
+      new_r->u.allowed.type_list = old_r->u.allowed.type_list;
+      new_r->u.allowed.label
+       = data->label_map (old_r->u.allowed.label, data->label_map_data);
+      break;
 
-static bool
-can_be_reached_by_runtime (sbitmap contains_stmt, struct eh_region_d *r)
-{
-  struct eh_region_d *i = r->inner;
-  unsigned n;
-  bitmap_iterator bi;
+    case ERT_MUST_NOT_THROW:
+      new_r->u.must_not_throw = old_r->u.must_not_throw;
+      break;
+    }
 
-  if (TEST_BIT (contains_stmt, r->region_number))
-    return true;
-  if (r->aka)
-    EXECUTE_IF_SET_IN_BITMAP (r->aka, 0, n, bi)
-      if (TEST_BIT (contains_stmt, n))
-      return true;
-  if (!i)
-    return false;
-  while (1)
+  for (old_lp = old_r->landing_pads; old_lp ; old_lp = old_lp->next_lp)
     {
-      /* It is pointless to look into MUST_NOT_THROW
-         or dive into subregions.  They never unwind up.  */
-      if (i->type != ERT_MUST_NOT_THROW)
-       {
-         bool found = TEST_BIT (contains_stmt, i->region_number);
-         if (!found && i->aka)
-           EXECUTE_IF_SET_IN_BITMAP (i->aka, 0, n, bi)
-             if (TEST_BIT (contains_stmt, n))
-             {
-               found = true;
-               break;
-             }
-         /* We have nested region that contains throwing statement.
-            See if resuming might lead up to the resx or we get locally
-            caught sooner.  If we get locally caught sooner, we either
-            know region R is not reachable or it would have direct edge
-            from the EH resx and thus consider region reachable at
-            firest place.  */
-         if (found)
-           {
-             struct eh_region_d *i1 = i;
-             tree type_thrown = NULL_TREE;
+      /* Don't bother copying unused landing pads.  */
+      if (old_lp->post_landing_pad == NULL)
+       continue;
 
-             if (i1->type == ERT_THROW)
-               {
-                 type_thrown = i1->u.eh_throw.type;
-                 i1 = i1->outer;
-               }
-             for (; i1 != r; i1 = i1->outer)
-               if (reachable_next_level (i1, type_thrown, NULL,
-                                         false) >= RNL_CAUGHT)
-                 break;
-             if (i1 == r)
-               return true;
-           }
-       }
-      /* If there are sub-regions, process them.  */
-      if (i->type != ERT_MUST_NOT_THROW && i->inner)
-       i = i->inner;
-      /* If there are peers, process them.  */
-      else if (i->next_peer)
-       i = i->next_peer;
-      /* Otherwise, step back up the tree to the next peer.  */
-      else
-       {
-         do
-           {
-             i = i->outer;
-             if (i == r)
-               return false;
-           }
-         while (i->next_peer == NULL);
-         i = i->next_peer;
-       }
+      new_lp = gen_eh_landing_pad (new_r);
+      slot = pointer_map_insert (data->eh_map, (void *)old_lp);
+      gcc_assert (*slot == NULL);
+      *slot = (void *)new_lp;
+
+      new_lp->post_landing_pad
+       = data->label_map (old_lp->post_landing_pad, data->label_map_data);
+      EH_LANDING_PAD_NR (new_lp->post_landing_pad) = new_lp->index;
     }
+
+  for (old_r = old_r->inner; old_r ; old_r = old_r->next_peer)
+    duplicate_eh_regions_1 (data, old_r, new_r);
 }
 
-/* Bring region R to the root of tree.  */
+/* Duplicate the EH regions from IFUN rooted at COPY_REGION into
+   the current function and root the tree below OUTER_REGION.
+   The special case of COPY_REGION of NULL means all regions.
+   Remap labels using MAP/MAP_DATA callback.  Return a pointer map
+   that allows the caller to remap uses of both EH regions and
+   EH landing pads.  */
 
-static void
-bring_to_root (struct eh_region_d *r)
+struct pointer_map_t *
+duplicate_eh_regions (struct function *ifun,
+                     eh_region copy_region, int outer_lp,
+                     duplicate_eh_regions_map map, void *map_data)
 {
-  struct eh_region_d **pp;
-  struct eh_region_d *outer = r->outer;
-  if (!r->outer)
-    return;
-  for (pp = &outer->inner; *pp != r; pp = &(*pp)->next_peer)
-    continue;
-  *pp = r->next_peer;
-  r->outer = NULL;
-  r->next_peer = cfun->eh->region_tree;
-  cfun->eh->region_tree = r;
-}
+  struct duplicate_eh_regions_data data;
+  eh_region outer_region;
 
-/* Return true if region R2 can be replaced by R1.  */
+#ifdef ENABLE_CHECKING
+  verify_eh_tree (ifun);
+#endif
 
-static bool
-eh_region_replaceable_by_p (const struct eh_region_d *r1,
-                           const struct eh_region_d *r2)
-{
-  /* Regions are semantically same if they are of same type,
-     have same label and type.  */
-  if (r1->type != r2->type)
-    return false;
-  if (r1->tree_label != r2->tree_label)
-    return false;
+  data.label_map = map;
+  data.label_map_data = map_data;
+  data.eh_map = pointer_map_create ();
 
-  /* Verify that also region type dependent data are the same.  */
-  switch (r1->type)
+  outer_region = get_eh_region_from_lp_number (outer_lp);
+  
+  /* Copy all the regions in the subtree.  */
+  if (copy_region)
+    duplicate_eh_regions_1 (&data, copy_region, outer_region);
+  else
     {
-      case ERT_MUST_NOT_THROW:
-      case ERT_CLEANUP:
-       break;
-      case ERT_TRY:
-       {
-         struct eh_region_d *c1, *c2;
-         for (c1 = r1->u.eh_try.eh_catch,
-              c2 = r2->u.eh_try.eh_catch;
-              c1 && c2;
-              c1 = c1->u.eh_catch.next_catch,
-              c2 = c2->u.eh_catch.next_catch)
-           if (!eh_region_replaceable_by_p (c1, c2))
-             return false;
-         if (c1 || c2)
-           return false;
-        }
-       break;
-      case ERT_CATCH:
-        if (!list_equal_p (r1->u.eh_catch.type_list, r2->u.eh_catch.type_list))
-         return false;
-        if (!list_equal_p (r1->u.eh_catch.filter_list,
-                          r2->u.eh_catch.filter_list))
-         return false;
-        break;
-      case ERT_ALLOWED_EXCEPTIONS:
-        if (!list_equal_p (r1->u.allowed.type_list, r2->u.allowed.type_list))
-         return false;
-       if (r1->u.allowed.filter != r2->u.allowed.filter)
-         return false;
-       break;
-      case ERT_THROW:
-       if (r1->u.eh_throw.type != r2->u.eh_throw.type)
-         return false;
-       break;
-      default:
-        gcc_unreachable ();
+      eh_region r;
+      for (r = ifun->eh->region_tree; r ; r = r->next_peer)
+       duplicate_eh_regions_1 (&data, r, outer_region);
     }
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    fprintf (dump_file, "Regions %i and %i match\n", r1->region_number,
-                                                    r2->region_number);
-  return true;
-}
 
-/* Replace region R2 by R1.  */
-
-static void
-replace_region (struct eh_region_d *r1, struct eh_region_d *r2)
-{
-  struct eh_region_d *next1 = r1->u.eh_try.eh_catch;
-  struct eh_region_d *next2 = r2->u.eh_try.eh_catch;
-  bool is_try = r1->type == ERT_TRY;
+#ifdef ENABLE_CHECKING
+  verify_eh_tree (cfun);
+#endif
 
-  gcc_assert (r1->type != ERT_CATCH);
-  remove_eh_handler_and_replace (r2, r1, false);
-  if (is_try)
-    {
-      while (next1)
-       {
-         r1 = next1;
-         r2 = next2;
-         gcc_assert (next1->type == ERT_CATCH);
-         gcc_assert (next2->type == ERT_CATCH);
-         next1 = next1->u.eh_catch.next_catch;
-         next2 = next2->u.eh_catch.next_catch;
-         remove_eh_handler_and_replace (r2, r1, false);
-       }
-    }
+  return data.eh_map;
 }
 
-/* Return hash value of type list T.  */
+/* Return the region that is outer to both REGION_A and REGION_B in IFUN.  */
 
-static hashval_t
-hash_type_list (tree t)
+eh_region
+eh_region_outermost (struct function *ifun, eh_region region_a,
+                    eh_region region_b)
 {
-  hashval_t val = 0;
-  for (; t; t = TREE_CHAIN (t))
-    val = iterative_hash_hashval_t (TREE_HASH (TREE_VALUE (t)), val);
-  return val;
-}
+  sbitmap b_outer;
+
+  gcc_assert (ifun->eh->region_array);
+  gcc_assert (ifun->eh->region_tree);
 
-/* Hash EH regions so semantically same regions get same hash value.  */
+  b_outer = sbitmap_alloc (VEC_length (eh_region, ifun->eh->region_array));
+  sbitmap_zero (b_outer);
 
-static hashval_t
-hash_eh_region (const void *r)
-{
-  const struct eh_region_d *region = (const struct eh_region_d *) r;
-  hashval_t val = region->type;
+  do
+    {
+      SET_BIT (b_outer, region_b->index);
+      region_b = region_b->outer;
+    }
+  while (region_b);
 
-  if (region->tree_label)
-    val = iterative_hash_hashval_t (LABEL_DECL_UID (region->tree_label), val);
-  switch (region->type)
+  do
     {
-      case ERT_MUST_NOT_THROW:
-      case ERT_CLEANUP:
-       break;
-      case ERT_TRY:
-       {
-         struct eh_region_d *c;
-         for (c = region->u.eh_try.eh_catch;
-              c; c = c->u.eh_catch.next_catch)
-           val = iterative_hash_hashval_t (hash_eh_region (c), val);
-        }
-       break;
-      case ERT_CATCH:
-        val = iterative_hash_hashval_t (hash_type_list
-                                         (region->u.eh_catch.type_list), val);
-        break;
-      case ERT_ALLOWED_EXCEPTIONS:
-        val = iterative_hash_hashval_t
-               (hash_type_list (region->u.allowed.type_list), val);
-        val = iterative_hash_hashval_t (region->u.allowed.filter, val);
+      if (TEST_BIT (b_outer, region_a->index))
        break;
-      case ERT_THROW:
-        val |= iterative_hash_hashval_t (TYPE_UID (region->u.eh_throw.type), val);
-       break;
-      default:
-        gcc_unreachable ();
+      region_a = region_a->outer;
     }
-  return val;
-}
-
-/* Return true if regions R1 and R2 are equal.  */
+  while (region_a);
 
+  sbitmap_free (b_outer);
+  return region_a;
+}
+\f
 static int
-eh_regions_equal_p (const void *r1, const void *r2)
+t2r_eq (const void *pentry, const void *pdata)
 {
-  return eh_region_replaceable_by_p ((const struct eh_region_d *) r1,
-                                    (const struct eh_region_d *) r2);
-}
+  const_tree const entry = (const_tree) pentry;
+  const_tree const data = (const_tree) pdata;
 
-/* Walk all peers of REGION and try to merge those regions
-   that are semantically equivalent.  Look into subregions
-   recursively too.  */
+  return TREE_PURPOSE (entry) == data;
+}
 
-static bool
-merge_peers (struct eh_region_d *region)
+static hashval_t
+t2r_hash (const void *pentry)
 {
-  struct eh_region_d *r1, *r2, *outer = NULL, *next;
-  bool merged = false;
-  int num_regions = 0;
-  if (region)
-    outer = region->outer;
-  else
-    return false;
+  const_tree const entry = (const_tree) pentry;
+  return TREE_HASH (TREE_PURPOSE (entry));
+}
 
-  /* First see if there is inner region equivalent to region
-     in question.  EH control flow is acyclic so we know we
-     can merge them.  */
-  if (outer)
-    for (r1 = region; r1; r1 = next)
-      {
-        next = r1->next_peer;
-       if (r1->type == ERT_CATCH)
-         continue;
-        if (eh_region_replaceable_by_p (r1->outer, r1))
-         {
-           replace_region (r1->outer, r1);
-           merged = true;
-         }
-       else
-         num_regions ++;
-      }
+void
+add_type_for_runtime (tree type)
+{
+  tree *slot;
 
-  /* Get new first region and try to match the peers
-     for equivalence.  */
-  if (outer)
-    region = outer->inner;
-  else
-    region = cfun->eh->region_tree;
+  /* If TYPE is NOP_EXPR, it means that it already is a runtime type.  */
+  if (TREE_CODE (type) == NOP_EXPR)
+    return;
 
-  /* There are few regions to inspect:
-     N^2 loop matching each region with each region
-     will do the job well.  */
-  if (num_regions < 10)
-    {
-      for (r1 = region; r1; r1 = r1->next_peer)
-       {
-         if (r1->type == ERT_CATCH)
-           continue;
-         for (r2 = r1->next_peer; r2; r2 = next)
-           {
-             next = r2->next_peer;
-             if (eh_region_replaceable_by_p (r1, r2))
-               {
-                 replace_region (r1, r2);
-                 merged = true;
-               }
-           }
-       }
-    }
-  /* Or use hashtable to avoid N^2 behaviour.  */
-  else
+  slot = (tree *) htab_find_slot_with_hash (type_to_runtime_map, type,
+                                           TREE_HASH (type), INSERT);
+  if (*slot == NULL)
     {
-      htab_t hash;
-      hash = htab_create (num_regions, hash_eh_region,
-                         eh_regions_equal_p, NULL);
-      for (r1 = region; r1; r1 = next)
-       {
-          void **slot;
-
-         next = r1->next_peer;
-         if (r1->type == ERT_CATCH)
-           continue;
-         slot = htab_find_slot (hash, r1, INSERT);
-         if (!*slot)
-           *slot = r1;
-         else
-           replace_region ((struct eh_region_d *) *slot, r1);
-       }
-      htab_delete (hash);
+      tree runtime = lang_hooks.eh_runtime_type (type);
+      *slot = tree_cons (type, runtime, NULL_TREE);
     }
-  for (r1 = region; r1; r1 = r1->next_peer)
-    merged |= merge_peers (r1->inner);
-  return merged;
 }
 
-/* Remove all regions whose labels are not reachable.
-   REACHABLE is bitmap of all regions that are used by the function
-   CONTAINS_STMT is bitmap of all regions that contains stmt (or NULL). */
-
-void
-remove_unreachable_regions (sbitmap reachable, sbitmap contains_stmt)
+tree
+lookup_type_for_runtime (tree type)
 {
-  int i;
-  struct eh_region_d *r;
-  VEC(eh_region,heap) *must_not_throws = VEC_alloc (eh_region, heap, 16);
-  struct eh_region_d *local_must_not_throw = NULL;
-  struct eh_region_d *first_must_not_throw = NULL;
+  tree *slot;
 
-  for (i = cfun->eh->last_region_number; i > 0; --i)
-    {
-      r = VEC_index (eh_region, cfun->eh->region_array, i);
-      if (!r || r->region_number != i)
-       continue;
-      if (!TEST_BIT (reachable, i) && !r->resume)
-       {
-         bool kill_it = true;
+  /* If TYPE is NOP_EXPR, it means that it already is a runtime type.  */
+  if (TREE_CODE (type) == NOP_EXPR)
+    return type;
 
-         r->tree_label = NULL;
-         switch (r->type)
-           {
-           case ERT_THROW:
-             /* Don't remove ERT_THROW regions if their outer region
-                is reachable.  */
-             if (r->outer && TEST_BIT (reachable, r->outer->region_number))
-               kill_it = false;
-             break;
-           case ERT_MUST_NOT_THROW:
-             /* MUST_NOT_THROW regions are implementable solely in the
-                runtime, but we need them when inlining function.
-
-                Keep them if outer region is not MUST_NOT_THROW a well
-                and if they contain some statement that might unwind through
-                them.  */
-             if ((!r->outer || r->outer->type != ERT_MUST_NOT_THROW)
-                 && (!contains_stmt
-                     || can_be_reached_by_runtime (contains_stmt, r)))
-               kill_it = false;
-             break;
-           case ERT_TRY:
-             {
-               /* TRY regions are reachable if any of its CATCH regions
-                  are reachable.  */
-               struct eh_region_d *c;
-               for (c = r->u.eh_try.eh_catch; c;
-                    c = c->u.eh_catch.next_catch)
-                 if (TEST_BIT (reachable, c->region_number))
-                   {
-                     kill_it = false;
-                     break;
-                   }
-               break;
-             }
+  slot = (tree *) htab_find_slot_with_hash (type_to_runtime_map, type,
+                                           TREE_HASH (type), NO_INSERT);
 
-           default:
-             break;
-           }
+  /* We should have always inserted the data earlier.  */
+  return TREE_VALUE (*slot);
+}
 
-         if (kill_it)
-           {
-             if (dump_file)
-               fprintf (dump_file, "Removing unreachable eh region %i\n",
-                        r->region_number);
-             remove_eh_handler (r);
-           }
-         else if (r->type == ERT_MUST_NOT_THROW)
-           {
-             if (!first_must_not_throw)
-               first_must_not_throw = r;
-             VEC_safe_push (eh_region, heap, must_not_throws, r);
-           }
-       }
-      else
-       if (r->type == ERT_MUST_NOT_THROW)
-         {
-           if (!local_must_not_throw)
-             local_must_not_throw = r;
-           if (r->outer)
-             VEC_safe_push (eh_region, heap, must_not_throws, r);
-         }
-    }
+\f
+/* Represent an entry in @TTypes for either catch actions
+   or exception filter actions.  */
+struct GTY(()) ttypes_filter {
+  tree t;
+  int filter;
+};
 
-  /* MUST_NOT_THROW regions without local handler are all the same; they
-     trigger terminate call in runtime.
-     MUST_NOT_THROW handled locally can differ in debug info associated
-     to std::terminate () call or if one is coming from Java and other
-     from C++ whether they call terminate or abort.  
+/* Compare ENTRY (a ttypes_filter entry in the hash table) with DATA
+   (a tree) for a @TTypes type node we are thinking about adding.  */
 
-     We merge all MUST_NOT_THROW regions handled by the run-time into one.
-     We alsobring all local MUST_NOT_THROW regions to the roots of EH tree
-     (since unwinding never continues to the outer region anyway).
-     If MUST_NOT_THROW with local handler is present in the tree, we use
-     that region to merge into, since it will remain in tree anyway;
-     otherwise we use first MUST_NOT_THROW.
-
-     Merging of locally handled regions needs changes to the CFG.  Crossjumping
-     should take care of this, by looking at the actual code and
-     ensuring that the cleanup actions are really the same.  */
-
-  if (local_must_not_throw)
-    first_must_not_throw = local_must_not_throw;
-
-  for (i = 0; VEC_iterate (eh_region, must_not_throws, i, r); i++)
-    {
-      if (!r->label && !r->tree_label && r != first_must_not_throw)
-       {
-         if (dump_file)
-           fprintf (dump_file, "Replacing MUST_NOT_THROW region %i by %i\n",
-                    r->region_number,
-                    first_must_not_throw->region_number);
-         remove_eh_handler_and_replace (r, first_must_not_throw, false);
-         first_must_not_throw->may_contain_throw |= r->may_contain_throw;
-       }
-      else
-       bring_to_root (r);
-    }
-  merge_peers (cfun->eh->region_tree);
-#ifdef ENABLE_CHECKING
-  verify_eh_tree (cfun);
-#endif
-  VEC_free (eh_region, heap, must_not_throws);
-}
-
-/* Return array mapping LABEL_DECL_UID to region such that region's tree_label
-   is identical to label.  */
-
-VEC (int, heap) *
-label_to_region_map (void)
-{
-  VEC (int, heap) * label_to_region = NULL;
-  int i;
-  int idx;
-
-  VEC_safe_grow_cleared (int, heap, label_to_region,
-                        cfun->cfg->last_label_uid + 1);
-  for (i = cfun->eh->last_region_number; i > 0; --i)
-    {
-      struct eh_region_d *r = VEC_index (eh_region, cfun->eh->region_array, i);
-      if (r && r->region_number == i
-         && r->tree_label && LABEL_DECL_UID (r->tree_label) >= 0)
-       {
-         if ((idx = VEC_index (int, label_to_region,
-                               LABEL_DECL_UID (r->tree_label))) != 0)
-             r->next_region_sharing_label =
-             VEC_index (eh_region, cfun->eh->region_array, idx);
-         else
-           r->next_region_sharing_label = NULL;
-         VEC_replace (int, label_to_region, LABEL_DECL_UID (r->tree_label),
-                      i);
-       }
-    }
-  return label_to_region;
-}
-
-/* Return number of EH regions.  */
-int
-num_eh_regions (void)
-{
-  return cfun->eh->last_region_number + 1;
-}
-
-/* Return next region sharing same label as REGION.  */
-
-int
-get_next_region_sharing_label (int region)
-{
-  struct eh_region_d *r;
-  if (!region)
-    return 0;
-  r = VEC_index (eh_region, cfun->eh->region_array, region);
-  if (!r || !r->next_region_sharing_label)
-    return 0;
-  return r->next_region_sharing_label->region_number;
-}
-
-/* Return bitmap of all labels that are handlers of must not throw regions.  */
-
-bitmap
-must_not_throw_labels (void)
-{
-  struct eh_region_d *i;
-  bitmap labels = BITMAP_ALLOC (NULL);
-
-  i = cfun->eh->region_tree;
-  if (! i)
-    return labels;
-
-  while (1)
-    {
-      if (i->type == ERT_MUST_NOT_THROW && i->tree_label
-          && LABEL_DECL_UID (i->tree_label) >= 0)
-        bitmap_set_bit (labels, LABEL_DECL_UID (i->tree_label));
-
-      /* If there are sub-regions, process them.  */
-      if (i->inner)
-       i = i->inner;
-      /* If there are peers, process them.  */
-      else if (i->next_peer)
-       i = i->next_peer;
-      /* Otherwise, step back up the tree to the next peer.  */
-      else
-       {
-         do {
-           i = i->outer;
-           if (i == NULL)
-             return labels;
-         } while (i->next_peer == NULL);
-         i = i->next_peer;
-       }
-    }
-}
-
-/* Set up EH labels for RTL.  */
-
-void
-convert_from_eh_region_ranges (void)
-{
-  int i, n = cfun->eh->last_region_number;
-
-  /* Most of the work is already done at the tree level.  All we need to
-     do is collect the rtl labels that correspond to the tree labels that
-     collect the rtl labels that correspond to the tree labels
-     we allocated earlier.  */
-  for (i = 1; i <= n; ++i)
-    {
-      struct eh_region_d *region;
-
-      region = VEC_index (eh_region, cfun->eh->region_array, i);
-      if (region && region->tree_label)
-       region->label = DECL_RTL_IF_SET (region->tree_label);
-    }
-}
-
-void
-find_exception_handler_labels (void)
-{
-  int i;
-
-  if (cfun->eh->region_tree == NULL)
-    return;
-
-  for (i = cfun->eh->last_region_number; i > 0; --i)
-    {
-      struct eh_region_d *region;
-      rtx lab;
-
-      region = VEC_index (eh_region, cfun->eh->region_array, i);
-      if (! region || region->region_number != i)
-       continue;
-      if (crtl->eh.built_landing_pads)
-       lab = region->landing_pad;
-      else
-       lab = region->label;
-    }
-}
-
-/* Returns true if the current function has exception handling regions.  */
-
-bool
-current_function_has_exception_handlers (void)
-{
-  int i;
-
-  for (i = cfun->eh->last_region_number; i > 0; --i)
-    {
-      struct eh_region_d *region;
-
-      region = VEC_index (eh_region, cfun->eh->region_array, i);
-      if (region
-         && region->region_number == i
-         && region->type != ERT_THROW)
-       return true;
-    }
-
-  return false;
-}
-\f
-/* A subroutine of duplicate_eh_regions.  Search the region tree under O
-   for the minimum and maximum region numbers.  Update *MIN and *MAX.  */
-
-static void
-duplicate_eh_regions_0 (eh_region o, int *min, int *max)
-{
-  int i;
-
-  if (o->aka)
-    {
-      i = bitmap_first_set_bit (o->aka);
-      if (i < *min)
-       *min = i;
-      i = bitmap_last_set_bit (o->aka);
-      if (i > *max)
-       *max = i;
-    }
-  if (o->region_number < *min)
-    *min = o->region_number;
-  if (o->region_number > *max)
-    *max = o->region_number;
-
-  if (o->inner)
-    {
-      o = o->inner;
-      duplicate_eh_regions_0 (o, min, max);
-      while (o->next_peer)
-       {
-         o = o->next_peer;
-         duplicate_eh_regions_0 (o, min, max);
-       }
-    }
-}
-
-/* A subroutine of duplicate_eh_regions.  Copy the region tree under OLD.
-   Root it at OUTER, and apply EH_OFFSET to the region number.  Don't worry
-   about the other internal pointers just yet, just the tree-like pointers.  */
-
-static eh_region
-duplicate_eh_regions_1 (eh_region old, eh_region outer, int eh_offset)
-{
-  eh_region ret, n;
-
-  ret = n = GGC_NEW (struct eh_region_d);
-
-  *n = *old;
-  n->outer = outer;
-  n->next_peer = NULL;
-  if (old->aka)
-    {
-      unsigned i;
-      bitmap_iterator bi;
-      n->aka = BITMAP_GGC_ALLOC ();
-
-      EXECUTE_IF_SET_IN_BITMAP (old->aka, 0, i, bi)
-      {
-       bitmap_set_bit (n->aka, i + eh_offset);
-       VEC_replace (eh_region, cfun->eh->region_array, i + eh_offset, n);
-      }
-    }
-
-  n->region_number += eh_offset;
-  VEC_replace (eh_region, cfun->eh->region_array, n->region_number, n);
-
-  if (old->inner)
-    {
-      old = old->inner;
-      n = n->inner = duplicate_eh_regions_1 (old, ret, eh_offset);
-      while (old->next_peer)
-       {
-         old = old->next_peer;
-         n = n->next_peer = duplicate_eh_regions_1 (old, ret, eh_offset);
-       }
-    }
-
-  return ret;
-}
-
-/* Look for first outer region of R (or R itself) that is
-   TRY region. Return NULL if none.  */
-
-static struct eh_region_d *
-find_prev_try (struct eh_region_d * r)
-{
-  for (; r && r->type != ERT_TRY; r = r->outer)
-    if (r->type == ERT_MUST_NOT_THROW
-       || (r->type == ERT_ALLOWED_EXCEPTIONS
-           && !r->u.allowed.type_list))
-      {
-       r = NULL;
-       break;
-      }
-  return r;
-}
-
-/* Duplicate the EH regions of IFUN, rooted at COPY_REGION, into current
-   function and root the tree below OUTER_REGION.  Remap labels using MAP
-   callback.  The special case of COPY_REGION of 0 means all regions.  */
-
-int
-duplicate_eh_regions (struct function *ifun, duplicate_eh_regions_map map,
-                     void *data, int copy_region, int outer_region)
-{
-  eh_region cur, outer, *splice;
-  int i, min_region, max_region, eh_offset, cfun_last_region_number;
-  int num_regions;
-
-  if (!ifun->eh)
-    return 0;
-#ifdef ENABLE_CHECKING
-  verify_eh_tree (ifun);
-#endif
-
-  /* Find the range of region numbers to be copied.  The interface we 
-     provide here mandates a single offset to find new number from old,
-     which means we must look at the numbers present, instead of the
-     count or something else.  */
-  if (copy_region > 0)
-    {
-      min_region = INT_MAX;
-      max_region = 0;
-
-      cur = VEC_index (eh_region, ifun->eh->region_array, copy_region);
-      duplicate_eh_regions_0 (cur, &min_region, &max_region);
-    }
-  else
-    {
-      min_region = 1;
-      max_region = ifun->eh->last_region_number;
-    }
-  num_regions = max_region - min_region + 1;
-  cfun_last_region_number = cfun->eh->last_region_number;
-  eh_offset = cfun_last_region_number + 1 - min_region;
-
-  /* If we've not yet created a region array, do so now.  */
-  cfun->eh->last_region_number = cfun_last_region_number + num_regions;
-  VEC_safe_grow_cleared (eh_region, gc, cfun->eh->region_array,
-                        cfun->eh->last_region_number + 1);
-
-  /* Locate the spot at which to insert the new tree.  */
-  if (outer_region > 0)
-    {
-      outer = VEC_index (eh_region, cfun->eh->region_array, outer_region);
-      if (outer)
-       splice = &outer->inner;
-      else
-       splice = &cfun->eh->region_tree;
-    }
-  else
-    {
-      outer = NULL;
-      splice = &cfun->eh->region_tree;
-    }
-  while (*splice)
-    splice = &(*splice)->next_peer;
-
-  if (!ifun->eh->region_tree)
-    {
-      if (outer)
-       for (i = cfun_last_region_number + 1;
-            i <= cfun->eh->last_region_number; i++)
-         {
-           VEC_replace (eh_region, cfun->eh->region_array, i, outer);
-           if (outer->aka == NULL)
-             outer->aka = BITMAP_GGC_ALLOC ();
-           bitmap_set_bit (outer->aka, i);
-         }
-      return eh_offset;
-    }
-
-  /* Copy all the regions in the subtree.  */
-  if (copy_region > 0)
-    {
-      cur = VEC_index (eh_region, ifun->eh->region_array, copy_region);
-      *splice = duplicate_eh_regions_1 (cur, outer, eh_offset);
-    }
-  else
-    {
-      eh_region n;
-
-      cur = ifun->eh->region_tree;
-      *splice = n = duplicate_eh_regions_1 (cur, outer, eh_offset);
-      while (cur->next_peer)
-       {
-         cur = cur->next_peer;
-         n = n->next_peer = duplicate_eh_regions_1 (cur, outer, eh_offset);
-       }
-    }
-
-  /* Remap all the labels in the new regions.  */
-  for (i = cfun_last_region_number + 1;
-       VEC_iterate (eh_region, cfun->eh->region_array, i, cur); ++i)
-    if (cur && cur->tree_label)
-      cur->tree_label = map (cur->tree_label, data);
-
-  /* Remap all of the internal catch and cleanup linkages.  Since we 
-     duplicate entire subtrees, all of the referenced regions will have
-     been copied too.  And since we renumbered them as a block, a simple
-     bit of arithmetic finds us the index for the replacement region.  */
-  for (i = cfun_last_region_number + 1;
-       VEC_iterate (eh_region, cfun->eh->region_array, i, cur); ++i)
-    {
-      /* All removed EH that is toplevel in input function is now
-         in outer EH of output function.  */
-      if (cur == NULL)
-       {
-         gcc_assert (VEC_index
-                     (eh_region, ifun->eh->region_array,
-                      i - eh_offset) == NULL);
-         if (outer)
-           {
-             VEC_replace (eh_region, cfun->eh->region_array, i, outer);
-             if (outer->aka == NULL)
-               outer->aka = BITMAP_GGC_ALLOC ();
-             bitmap_set_bit (outer->aka, i);
-           }
-         continue;
-       }
-      if (i != cur->region_number)
-       continue;
-
-#define REMAP(REG) \
-       (REG) = VEC_index (eh_region, cfun->eh->region_array, \
-                          (REG)->region_number + eh_offset)
-
-      switch (cur->type)
-       {
-       case ERT_TRY:
-         if (cur->u.eh_try.eh_catch)
-           REMAP (cur->u.eh_try.eh_catch);
-         if (cur->u.eh_try.last_catch)
-           REMAP (cur->u.eh_try.last_catch);
-         break;
-
-       case ERT_CATCH:
-         if (cur->u.eh_catch.next_catch)
-           REMAP (cur->u.eh_catch.next_catch);
-         if (cur->u.eh_catch.prev_catch)
-           REMAP (cur->u.eh_catch.prev_catch);
-         break;
-
-       default:
-         break;
-       }
-
-#undef REMAP
-    }
-#ifdef ENABLE_CHECKING
-  verify_eh_tree (cfun);
-#endif
-
-  return eh_offset;
-}
-
-/* Return new copy of eh region OLD inside region NEW_OUTER.
-   Do not care about updating the tree otherwise.  */
-
-static struct eh_region_d *
-copy_eh_region_1 (struct eh_region_d *old, struct eh_region_d *new_outer)
-{
-  struct eh_region_d *new_eh = gen_eh_region (old->type, new_outer);
-  new_eh->u = old->u;
-  new_eh->tree_label = old->tree_label;
-  new_eh->may_contain_throw = old->may_contain_throw;
-  VEC_safe_grow (eh_region, gc, cfun->eh->region_array,
-                cfun->eh->last_region_number + 1);
-  VEC_replace (eh_region, cfun->eh->region_array, new_eh->region_number, new_eh);
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    fprintf (dump_file, "Copying region %i to %i\n", old->region_number, new_eh->region_number);
-  return new_eh;
-}
-
-/* Return new copy of eh region OLD inside region NEW_OUTER.  
-  
-   Copy whole catch-try chain if neccesary.  */
-
-static struct eh_region_d *
-copy_eh_region (struct eh_region_d *old, struct eh_region_d *new_outer)
-{
-  struct eh_region_d *r, *n, *old_try, *new_try, *ret = NULL;
-  VEC(eh_region,heap) *catch_list = NULL;
-
-  if (old->type != ERT_CATCH)
-    {
-      gcc_assert (old->type != ERT_TRY);
-      r = copy_eh_region_1 (old, new_outer);
-      return r;
-    }
-
-  /* Locate and copy corresponding TRY.  */
-  for (old_try = old->next_peer; old_try->type == ERT_CATCH; old_try = old_try->next_peer)
-    continue;
-  gcc_assert (old_try->type == ERT_TRY);
-  new_try = gen_eh_region_try (new_outer);
-  new_try->tree_label = old_try->tree_label;
-  new_try->may_contain_throw = old_try->may_contain_throw;
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    fprintf (dump_file, "Copying try-catch regions. Try: %i to %i\n",
-            old_try->region_number, new_try->region_number);
-  VEC_safe_grow (eh_region, gc, cfun->eh->region_array,
-                cfun->eh->last_region_number + 1);
-  VEC_replace (eh_region, cfun->eh->region_array, new_try->region_number, new_try);
-
-  /* In order to keep CATCH list in order, we need to copy in reverse order.  */
-  for (r = old_try->u.eh_try.last_catch; r->type == ERT_CATCH; r = r->next_peer)
-    VEC_safe_push (eh_region, heap, catch_list, r);
-
-  while (VEC_length (eh_region, catch_list))
-    {
-      r = VEC_pop (eh_region, catch_list);
-
-      /* Duplicate CATCH.  */
-      n = gen_eh_region_catch (new_try, r->u.eh_catch.type_list);
-      n->tree_label = r->tree_label;
-      n->may_contain_throw = r->may_contain_throw;
-      VEC_safe_grow (eh_region, gc, cfun->eh->region_array,
-                    cfun->eh->last_region_number + 1);
-      VEC_replace (eh_region, cfun->eh->region_array, n->region_number, n);
-      n->tree_label = r->tree_label;
-
-      if (dump_file && (dump_flags & TDF_DETAILS))
-        fprintf (dump_file, "Copying try-catch regions. Catch: %i to %i\n",
-                r->region_number, n->region_number);
-      if (r == old)
-       ret = n;
-    }
-  VEC_free (eh_region, heap, catch_list);
-  gcc_assert (ret);
-  return ret;
-}
-
-/* Callback for forach_reachable_handler that push REGION into single VECtor DATA.  */
-
-static void
-push_reachable_handler (struct eh_region_d *region, void *data)
-{
-  VEC(eh_region,heap) **trace = (VEC(eh_region,heap) **) data;
-  VEC_safe_push (eh_region, heap, *trace, region);
-}
-
-/* Redirect EH edge E that to NEW_DEST_LABEL.
-   IS_RESX, INLINABLE_CALL and REGION_NMUBER match the parameter of
-   foreach_reachable_handler.  */
-
-struct eh_region_d *
-redirect_eh_edge_to_label (edge e, tree new_dest_label, bool is_resx,
-                          bool inlinable_call, int region_number)
-{
-  struct eh_region_d *outer;
-  struct eh_region_d *region;
-  VEC (eh_region, heap) * trace = NULL;
-  int i;
-  int start_here = -1;
-  basic_block old_bb = e->dest;
-  struct eh_region_d *old, *r = NULL;
-  bool update_inplace = true;
-  edge_iterator ei;
-  edge e2;
-
-  /* If there is only one EH edge, we don't need to duplicate;
-     just update labels in the tree.  */
-  FOR_EACH_EDGE (e2, ei, old_bb->preds)
-    if ((e2->flags & EDGE_EH) && e2 != e)
-      {
-        update_inplace = false;
-        break;
-      }
-
-  region = VEC_index (eh_region, cfun->eh->region_array, region_number);
-  gcc_assert (region);
-
-  foreach_reachable_handler (region_number, is_resx, inlinable_call,
-                            push_reachable_handler, &trace);
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    {
-      dump_eh_tree (dump_file, cfun);
-      fprintf (dump_file, "Trace: ");
-      for (i = 0; i < (int) VEC_length (eh_region, trace); i++)
-       fprintf (dump_file, " %i", VEC_index (eh_region, trace, i)->region_number);
-      fprintf (dump_file, " inplace: %i\n", update_inplace);
-    }
-
-  if (update_inplace)
-    {
-      /* In easy route just walk trace and update all occurences of the label.  */
-      for (i = 0; i < (int) VEC_length (eh_region, trace); i++)
-       {
-         r = VEC_index (eh_region, trace, i);
-         if (r->tree_label && label_to_block (r->tree_label) == old_bb)
-           {
-             r->tree_label = new_dest_label;
-             if (dump_file && (dump_flags & TDF_DETAILS))
-               fprintf (dump_file, "Updating label for region %i\n",
-                        r->region_number);
-           }
-       }
-      r = region;
-    }
-  else
-    {
-      /* Now look for outermost handler that reffers to the basic block in question.
-         We start our duplication there.  */
-      for (i = 0; i < (int) VEC_length (eh_region, trace); i++)
-       {
-         r = VEC_index (eh_region, trace, i);
-         if (r->tree_label && label_to_block (r->tree_label) == old_bb)
-           start_here = i;
-       }
-      outer = VEC_index (eh_region, trace, start_here)->outer;
-      gcc_assert (start_here >= 0);
-
-      /* And now do the dirty job!  */
-      for (i = start_here; i >= 0; i--)
-       {
-         old = VEC_index (eh_region, trace, i);
-         gcc_assert (!outer || old->outer != outer->outer);
-
-         /* Copy region and update label.  */
-         r = copy_eh_region (old, outer);
-         VEC_replace (eh_region, trace, i, r);
-         if (r->tree_label && label_to_block (r->tree_label) == old_bb)
-           {
-             r->tree_label = new_dest_label;
-             if (dump_file && (dump_flags & TDF_DETAILS))
-               fprintf (dump_file, "Updating label for region %i\n",
-                        r->region_number);
-           }
-
-         /* We got into copying CATCH.  copy_eh_region already did job
-            of copying all catch blocks corresponding to the try.  Now
-            we need to update labels in all of them and see trace.
-
-            We continue nesting into TRY region corresponding to CATCH:
-            When duplicating EH tree contaiing subregions of CATCH,
-            the CATCH region itself is never inserted to trace so we
-            never get here anyway.  */
-         if (r->type == ERT_CATCH)
-           {
-             /* Walk other catch regions we copied and update labels as needed.  */
-             for (r = r->next_peer; r->type == ERT_CATCH; r = r->next_peer)
-               if (r->tree_label && label_to_block (r->tree_label) == old_bb)
-                 {
-                   r->tree_label = new_dest_label;
-                   if (dump_file && (dump_flags & TDF_DETAILS))
-                     fprintf (dump_file, "Updating label for region %i\n",
-                              r->region_number);
-                 }
-              gcc_assert (r->type == ERT_TRY);
-
-              /* Skip sibling catch regions from the trace.
-                 They are already updated.  */
-              while (i > 0 && VEC_index (eh_region, trace, i - 1)->outer == old->outer)
-                {
-                  gcc_assert (VEC_index (eh_region, trace, i - 1)->type == ERT_CATCH);
-                  i--;
-                }
-            }
-
-         outer = r;
-       }
-        
-      if (is_resx || region->type == ERT_THROW)
-       r = copy_eh_region (region, outer);
-    }
-
-  VEC_free (eh_region, heap, trace);
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    {
-      dump_eh_tree (dump_file, cfun);
-      fprintf (dump_file, "New region: %i\n", r->region_number);
-    }
-  return r;
-}
-
-/* Return region number of region that is outer to both if REGION_A and
-   REGION_B in IFUN.  */
-
-int
-eh_region_outermost (struct function *ifun, int region_a, int region_b)
-{
-  struct eh_region_d *rp_a, *rp_b;
-  sbitmap b_outer;
-
-  gcc_assert (ifun->eh->last_region_number > 0);
-  gcc_assert (ifun->eh->region_tree);
-
-  rp_a = VEC_index (eh_region, ifun->eh->region_array, region_a);
-  rp_b = VEC_index (eh_region, ifun->eh->region_array, region_b);
-  gcc_assert (rp_a != NULL);
-  gcc_assert (rp_b != NULL);
-
-  b_outer = sbitmap_alloc (ifun->eh->last_region_number + 1);
-  sbitmap_zero (b_outer);
-
-  do
-    {
-      SET_BIT (b_outer, rp_b->region_number);
-      rp_b = rp_b->outer;
-    }
-  while (rp_b);
-
-  do
-    {
-      if (TEST_BIT (b_outer, rp_a->region_number))
-       {
-         sbitmap_free (b_outer);
-         return rp_a->region_number;
-       }
-      rp_a = rp_a->outer;
-    }
-  while (rp_a);
-
-  sbitmap_free (b_outer);
-  return -1;
-}
-\f
-static int
-t2r_eq (const void *pentry, const void *pdata)
-{
-  const_tree const entry = (const_tree) pentry;
-  const_tree const data = (const_tree) pdata;
-
-  return TREE_PURPOSE (entry) == data;
-}
-
-static hashval_t
-t2r_hash (const void *pentry)
-{
-  const_tree const entry = (const_tree) pentry;
-  return TREE_HASH (TREE_PURPOSE (entry));
-}
-
-void
-add_type_for_runtime (tree type)
-{
-  tree *slot;
-
-  /* If TYPE is NOP_EXPR, it means that it already is a runtime type.  */
-  if (TREE_CODE (type) == NOP_EXPR)
-    return;
-
-  slot = (tree *) htab_find_slot_with_hash (type_to_runtime_map, type,
-                                           TREE_HASH (type), INSERT);
-  if (*slot == NULL)
-    {
-      tree runtime = lang_hooks.eh_runtime_type (type);
-      *slot = tree_cons (type, runtime, NULL_TREE);
-    }
-}
-
-tree
-lookup_type_for_runtime (tree type)
-{
-  tree *slot;
-
-  /* If TYPE is NOP_EXPR, it means that it already is a runtime type.  */
-  if (TREE_CODE (type) == NOP_EXPR)
-    return type;
-
-  slot = (tree *) htab_find_slot_with_hash (type_to_runtime_map, type,
-                                           TREE_HASH (type), NO_INSERT);
-
-  /* We should have always inserted the data earlier.  */
-  return TREE_VALUE (*slot);
-}
-
-\f
-/* Represent an entry in @TTypes for either catch actions
-   or exception filter actions.  */
-struct GTY(()) ttypes_filter {
-  tree t;
-  int filter;
-};
-
-/* Compare ENTRY (a ttypes_filter entry in the hash table) with DATA
-   (a tree) for a @TTypes type node we are thinking about adding.  */
-
-static int
-ttypes_filter_eq (const void *pentry, const void *pdata)
-{
-  const struct ttypes_filter *const entry
-    = (const struct ttypes_filter *) pentry;
-  const_tree const data = (const_tree) pdata;
+static int
+ttypes_filter_eq (const void *pentry, const void *pdata)
+{
+  const struct ttypes_filter *const entry
+    = (const struct ttypes_filter *) pentry;
+  const_tree const data = (const_tree) pdata;
 
   return entry->t == data;
 }
@@ -1770,7 +758,7 @@ ehspec_filter_hash (const void *pentry)
   return h;
 }
 
-/* Add TYPE (which may be NULL) to crtl->eh.ttype_data, using TYPES_HASH
+/* Add TYPE (which may be NULL) to cfun->eh->ttype_data, using TYPES_HASH
    to speed up the search.  Return the filter value to be used.  */
 
 static int
@@ -1787,16 +775,16 @@ add_ttypes_entry (htab_t ttypes_hash, tree type)
 
       n = XNEW (struct ttypes_filter);
       n->t = type;
-      n->filter = VEC_length (tree, crtl->eh.ttype_data) + 1;
+      n->filter = VEC_length (tree, cfun->eh->ttype_data) + 1;
       *slot = n;
 
-      VEC_safe_push (tree, gc, crtl->eh.ttype_data, type);
+      VEC_safe_push (tree, gc, cfun->eh->ttype_data, type);
     }
 
   return n->filter;
 }
 
-/* Add LIST to crtl->eh.ehspec_data, using EHSPEC_HASH and TYPES_HASH
+/* Add LIST to cfun->eh->ehspec_data, using EHSPEC_HASH and TYPES_HASH
    to speed up the search.  Return the filter value to be used.  */
 
 static int
@@ -1811,391 +799,171 @@ add_ehspec_entry (htab_t ehspec_hash, htab_t ttypes_hash, tree list)
 
   if ((n = *slot) == NULL)
     {
+      int len;
+
+      if (targetm.arm_eabi_unwinder)
+       len = VEC_length (tree, cfun->eh->ehspec_data.arm_eabi);
+      else
+       len = VEC_length (uchar, cfun->eh->ehspec_data.other);
+
       /* Filter value is a -1 based byte index into a uleb128 buffer.  */
 
       n = XNEW (struct ttypes_filter);
       n->t = list;
-      n->filter = -(VARRAY_ACTIVE_SIZE (crtl->eh.ehspec_data) + 1);
+      n->filter = -(len + 1);
       *slot = n;
 
       /* Generate a 0 terminated list of filter values.  */
       for (; list ; list = TREE_CHAIN (list))
        {
          if (targetm.arm_eabi_unwinder)
-           VARRAY_PUSH_TREE (crtl->eh.ehspec_data, TREE_VALUE (list));
+           VEC_safe_push (tree, gc, cfun->eh->ehspec_data.arm_eabi,
+                          TREE_VALUE (list));
          else
            {
              /* Look up each type in the list and encode its filter
                 value as a uleb128.  */
-             push_uleb128 (&crtl->eh.ehspec_data,
-                 add_ttypes_entry (ttypes_hash, TREE_VALUE (list)));
-           }
-       }
-      if (targetm.arm_eabi_unwinder)
-       VARRAY_PUSH_TREE (crtl->eh.ehspec_data, NULL_TREE);
-      else
-       VARRAY_PUSH_UCHAR (crtl->eh.ehspec_data, 0);
-    }
-
-  return n->filter;
-}
-
-/* Generate the action filter values to be used for CATCH and
-   ALLOWED_EXCEPTIONS regions.  When using dwarf2 exception regions,
-   we use lots of landing pads, and so every type or list can share
-   the same filter value, which saves table space.  */
-
-static void
-assign_filter_values (void)
-{
-  int i;
-  htab_t ttypes, ehspec;
-
-  crtl->eh.ttype_data = VEC_alloc (tree, gc, 16);
-  if (targetm.arm_eabi_unwinder)
-    VARRAY_TREE_INIT (crtl->eh.ehspec_data, 64, "ehspec_data");
-  else
-    VARRAY_UCHAR_INIT (crtl->eh.ehspec_data, 64, "ehspec_data");
-
-  ttypes = htab_create (31, ttypes_filter_hash, ttypes_filter_eq, free);
-  ehspec = htab_create (31, ehspec_filter_hash, ehspec_filter_eq, free);
-
-  for (i = cfun->eh->last_region_number; i > 0; --i)
-    {
-      struct eh_region_d *r;
-
-      r = VEC_index (eh_region, cfun->eh->region_array, i);
-
-      /* Mind we don't process a region more than once.  */
-      if (!r || r->region_number != i)
-       continue;
-
-      switch (r->type)
-       {
-       case ERT_CATCH:
-         /* Whatever type_list is (NULL or true list), we build a list
-            of filters for the region.  */
-         r->u.eh_catch.filter_list = NULL_TREE;
-
-         if (r->u.eh_catch.type_list != NULL)
-           {
-             /* Get a filter value for each of the types caught and store
-                them in the region's dedicated list.  */
-             tree tp_node = r->u.eh_catch.type_list;
-
-             for (;tp_node; tp_node = TREE_CHAIN (tp_node))
-               {
-                 int flt = add_ttypes_entry (ttypes, TREE_VALUE (tp_node));
-                 tree flt_node = build_int_cst (NULL_TREE, flt);
-
-                 r->u.eh_catch.filter_list
-                   = tree_cons (NULL_TREE, flt_node, r->u.eh_catch.filter_list);
-               }
+             push_uleb128 (&cfun->eh->ehspec_data.other,
+                           add_ttypes_entry (ttypes_hash, TREE_VALUE (list)));
            }
-         else
-           {
-             /* Get a filter value for the NULL list also since it will need
-                an action record anyway.  */
-             int flt = add_ttypes_entry (ttypes, NULL);
-             tree flt_node = build_int_cst (NULL_TREE, flt);
-
-             r->u.eh_catch.filter_list
-               = tree_cons (NULL_TREE, flt_node, r->u.eh_catch.filter_list);
-           }
-
-         break;
-
-       case ERT_ALLOWED_EXCEPTIONS:
-         r->u.allowed.filter
-           = add_ehspec_entry (ehspec, ttypes, r->u.allowed.type_list);
-         break;
-
-       default:
-         break;
-       }
-    }
-
-  htab_delete (ttypes);
-  htab_delete (ehspec);
-}
-
-/* Emit SEQ into basic block just before INSN (that is assumed to be
-   first instruction of some existing BB and return the newly
-   produced block.  */
-static basic_block
-emit_to_new_bb_before (rtx seq, rtx insn)
-{
-  rtx last;
-  basic_block bb;
-  edge e;
-  edge_iterator ei;
-
-  /* If there happens to be a fallthru edge (possibly created by cleanup_cfg
-     call), we don't want it to go into newly created landing pad or other EH
-     construct.  */
-  for (ei = ei_start (BLOCK_FOR_INSN (insn)->preds); (e = ei_safe_edge (ei)); )
-    if (e->flags & EDGE_FALLTHRU)
-      force_nonfallthru (e);
-    else
-      ei_next (&ei);
-  last = emit_insn_before (seq, insn);
-  if (BARRIER_P (last))
-    last = PREV_INSN (last);
-  bb = create_basic_block (seq, last, BLOCK_FOR_INSN (insn)->prev_bb);
-  update_bb_for_insn (bb);
-  bb->flags |= BB_SUPERBLOCK;
-  return bb;
-}
-
-/* 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_d *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:
-         /* It is possible that TRY region is kept alive only because some of
-            contained catch region still have RESX instruction but they are
-            reached via their copies.  In this case we need to do nothing.  */
-         if (!region->u.eh_try.eh_catch->label)
-           break;
-
-         /* ??? 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_d *c;
-           for (c = region->u.eh_try.eh_catch; c ; c = c->u.eh_catch.next_catch)
-             {
-               if (c->u.eh_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.eh_catch.type_list;
-                   tree flt_node = c->u.eh_catch.filter_list;
-
-                   for (; tp_node; )
-                     {
-                       emit_cmp_and_jump_insns
-                         (crtl->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.  */
-         gcc_assert (!region->resume);
-         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.eh_try.eh_catch->label);
-
-         break;
-
-       case ERT_ALLOWED_EXCEPTIONS:
-         if (!region->label)
-           break;
-         region->post_landing_pad = gen_label_rtx ();
-
-         start_sequence ();
-
-         emit_label (region->post_landing_pad);
-
-         emit_cmp_and_jump_insns (crtl->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.  */
-         gcc_assert (!region->resume);
-         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 ();
        }
+      if (targetm.arm_eabi_unwinder)
+       VEC_safe_push (tree, gc, cfun->eh->ehspec_data.arm_eabi, NULL_TREE);
+      else
+       VEC_safe_push (uchar, gc, cfun->eh->ehspec_data.other, 0);
     }
+
+  return n->filter;
 }
 
-/* Replace RESX patterns with jumps to the next handler if any, or calls to
-   _Unwind_Resume otherwise.  */
+/* Generate the action filter values to be used for CATCH and
+   ALLOWED_EXCEPTIONS regions.  When using dwarf2 exception regions,
+   we use lots of landing pads, and so every type or list can share
+   the same filter value, which saves table space.  */
 
-static void
-connect_post_landing_pads (void)
+void
+assign_filter_values (void)
 {
   int i;
+  htab_t ttypes, ehspec;
+  eh_region r;
+  eh_catch c;
 
-  for (i = cfun->eh->last_region_number; i > 0; --i)
-    {
-      struct eh_region_d *region;
-      struct eh_region_d *outer;
-      rtx seq;
-      rtx barrier;
-      rtx resume_list;
+  cfun->eh->ttype_data = VEC_alloc (tree, gc, 16);
+  if (targetm.arm_eabi_unwinder)
+    cfun->eh->ehspec_data.arm_eabi = VEC_alloc (tree, gc, 64);
+  else
+    cfun->eh->ehspec_data.other = VEC_alloc (uchar, gc, 64);
 
-      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;
+  ttypes = htab_create (31, ttypes_filter_hash, ttypes_filter_eq, free);
+  ehspec = htab_create (31, ehspec_filter_hash, ehspec_filter_eq, free);
 
-      /* If there is no RESX, or it has been deleted by flow, there's
-        nothing to fix up.  */
-      if (! region->resume)
+  for (i = 1; VEC_iterate (eh_region, cfun->eh->region_array, i, r); ++i)
+    {
+      if (r == NULL)
        continue;
 
-      /* Search for another landing pad in this function.  */
-      for (outer = region->outer; outer ; outer = outer->outer)
-       if (outer->post_landing_pad)
-         break;
-
-      for (resume_list = region->resume; resume_list;
-          resume_list = (GET_CODE (resume_list) == INSN_LIST
-                         ? XEXP (resume_list, 1) : NULL_RTX))
+      switch (r->type)
        {
-         rtx resume = (GET_CODE (resume_list) == INSN_LIST
-                       ? XEXP (resume_list, 0) : resume_list);
-          if (INSN_DELETED_P (resume))
-           continue;
-         start_sequence ();
-
-         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
+       case ERT_TRY:
+         for (c = r->u.eh_try.first_catch; c ; c = c->next_catch)
            {
-             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 ()));
+             /* Whatever type_list is (NULL or true list), we build a list
+                of filters for the region.  */
+             c->filter_list = NULL_TREE;
+
+             if (c->type_list != NULL)
+               {
+                 /* Get a filter value for each of the types caught and store
+                    them in the region's dedicated list.  */
+                 tree tp_node = c->type_list;
+
+                 for ( ; tp_node; tp_node = TREE_CHAIN (tp_node))
+                   {
+                     int flt = add_ttypes_entry (ttypes, TREE_VALUE (tp_node));
+                     tree flt_node = build_int_cst (NULL_TREE, flt);
+
+                     c->filter_list
+                       = tree_cons (NULL_TREE, flt_node, c->filter_list);
+                   }
+               }
+             else
+               {
+                 /* Get a filter value for the NULL list also since it
+                    will need an action record anyway.  */
+                 int flt = add_ttypes_entry (ttypes, NULL);
+                 tree flt_node = build_int_cst (NULL_TREE, flt);
+
+                 c->filter_list
+                   = tree_cons (NULL_TREE, flt_node, NULL);
+               }
            }
+         break;
 
-         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);
-       }
+       case ERT_ALLOWED_EXCEPTIONS:
+         r->u.allowed.filter
+           = add_ehspec_entry (ehspec, ttypes, r->u.allowed.type_list);
+         break;
 
-      /* ??? 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);
+       default:
+         break;
+       }
     }
+
+  htab_delete (ttypes);
+  htab_delete (ehspec);
 }
 
+/* Emit SEQ into basic block just before INSN (that is assumed to be
+   first instruction of some existing BB and return the newly
+   produced block.  */
+static basic_block
+emit_to_new_bb_before (rtx seq, rtx insn)
+{
+  rtx last;
+  basic_block bb;
+  edge e;
+  edge_iterator ei;
+
+  /* If there happens to be a fallthru edge (possibly created by cleanup_cfg
+     call), we don't want it to go into newly created landing pad or other EH
+     construct.  */
+  for (ei = ei_start (BLOCK_FOR_INSN (insn)->preds); (e = ei_safe_edge (ei)); )
+    if (e->flags & EDGE_FALLTHRU)
+      force_nonfallthru (e);
+    else
+      ei_next (&ei);
+  last = emit_insn_before (seq, insn);
+  if (BARRIER_P (last))
+    last = PREV_INSN (last);
+  bb = create_basic_block (seq, last, BLOCK_FOR_INSN (insn)->prev_bb);
+  update_bb_for_insn (bb);
+  bb->flags |= BB_SUPERBLOCK;
+  return bb;
+}
 \f
+/* Expand the extra code needed at landing pads for dwarf2 unwinding.  */
+
 static void
 dw2_build_landing_pads (void)
 {
   int i;
+  eh_landing_pad lp;
 
-  for (i = cfun->eh->last_region_number; i > 0; --i)
+  for (i = 1; VEC_iterate (eh_landing_pad, cfun->eh->lp_array, i, lp); ++i)
     {
-      struct eh_region_d *region;
-      rtx seq;
+      eh_region region;
       basic_block bb;
+      rtx seq;
       edge e;
 
-      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 (region->type != ERT_CLEANUP
-         && region->type != ERT_TRY
-         && region->type != ERT_ALLOWED_EXCEPTIONS)
-       continue;
-
-      if (!region->post_landing_pad)
+      if (lp == NULL || lp->post_landing_pad == NULL)
        continue;
 
       start_sequence ();
 
-      region->landing_pad = gen_label_rtx ();
-      emit_label (region->landing_pad);
+      lp->landing_pad = gen_label_rtx ();
+      emit_label (lp->landing_pad);
 
 #ifdef HAVE_exception_receiver
       if (HAVE_exception_receiver)
@@ -2209,16 +977,19 @@ dw2_build_landing_pads (void)
 #endif
          { /* Nothing */ }
 
-      emit_move_insn (crtl->eh.exc_ptr,
-                     gen_rtx_REG (ptr_mode, EH_RETURN_DATA_REGNO (0)));
-      emit_move_insn (crtl->eh.filter,
-                     gen_rtx_REG (targetm.eh_return_filter_mode (),
-                                  EH_RETURN_DATA_REGNO (1)));
+      region = lp->region;
+      if (region->exc_ptr_reg)
+       emit_move_insn (region->exc_ptr_reg,
+                       gen_rtx_REG (ptr_mode, EH_RETURN_DATA_REGNO (0)));
+      if (region->filter_reg)
+       emit_move_insn (region->filter_reg,
+                       gen_rtx_REG (targetm.eh_return_filter_mode (),
+                                    EH_RETURN_DATA_REGNO (1)));
 
       seq = get_insns ();
       end_sequence ();
 
-      bb = emit_to_new_bb_before (seq, region->post_landing_pad);
+      bb = emit_to_new_bb_before (seq, label_rtx (lp->post_landing_pad));
       e = make_edge (bb, bb->next_bb, EDGE_FALLTHRU);
       e->count = bb->count;
       e->probability = REG_BR_PROB_BASE;
@@ -2226,140 +997,71 @@ dw2_build_landing_pads (void)
 }
 
 \f
-struct sjlj_lp_info
-{
-  int directly_reachable;
-  int action_index;
-  int dispatch_index;
-  int call_site_index;
-};
-
-static bool
-sjlj_find_directly_reachable_regions (struct sjlj_lp_info *lp_info)
-{
-  rtx insn;
-  bool found_one = false;
-
-  for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
-    {
-      struct eh_region_d *region;
-      enum reachable_code rc;
-      tree type_thrown;
-      rtx note;
-
-      if (! INSN_P (insn))
-       continue;
-
-      note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
-      if (!note || INTVAL (XEXP (note, 0)) <= 0)
-       continue;
-
-      region = VEC_index (eh_region, cfun->eh->region_array, INTVAL (XEXP (note, 0)));
-      if (!region)
-       continue;
-
-      type_thrown = NULL_TREE;
-      if (region->type == ERT_THROW)
-       {
-         type_thrown = region->u.eh_throw.type;
-         region = region->outer;
-       }
+static VEC (int, heap) *sjlj_lp_call_site_index;
 
-      /* Find the first containing region that might handle the exception.
-        That's the landing pad to which we will transfer control.  */
-      rc = RNL_NOT_CAUGHT;
-      for (; region; region = region->outer)
-       {
-         rc = reachable_next_level (region, type_thrown, NULL, false);
-         if (rc != RNL_NOT_CAUGHT)
-           break;
-       }
-      if (rc == RNL_MAYBE_CAUGHT || rc == RNL_CAUGHT)
-       {
-         lp_info[region->region_number].directly_reachable = 1;
-         found_one = true;
-       }
-    }
-
-  return found_one;
-}
+/* Process all active landing pads.  Assign each one a compact dispatch
+   index, and a call-site index.  */
 
-static void
-sjlj_assign_call_site_values (rtx dispatch_label, struct sjlj_lp_info *lp_info)
+static int
+sjlj_assign_call_site_values (void)
 {
   htab_t ar_hash;
-  int i, index;
-
-  /* First task: build the action table.  */
+  int i, disp_index;
+  eh_landing_pad lp;
 
-  VARRAY_UCHAR_INIT (crtl->eh.action_record_data, 64, "action_record_data");
+  crtl->eh.action_record_data = VEC_alloc (uchar, gc, 64);
   ar_hash = htab_create (31, action_record_hash, action_record_eq, free);
 
-  for (i = cfun->eh->last_region_number; i > 0; --i)
-    if (lp_info[i].directly_reachable)
+  disp_index = 0;
+  call_site_base = 1;
+  for (i = 1; VEC_iterate (eh_landing_pad, cfun->eh->lp_array, i, lp); ++i)
+    if (lp && lp->post_landing_pad)
       {
-       struct eh_region_d *r =
-         VEC_index (eh_region, cfun->eh->region_array, i);
+       int action, call_site;
 
-       r->landing_pad = dispatch_label;
-       lp_info[i].action_index = collect_one_action_chain (ar_hash, r);
-       if (lp_info[i].action_index != -1)
+       /* First: build the action table.  */
+       action = collect_one_action_chain (ar_hash, lp->region);
+       if (action != -1)
          crtl->uses_eh_lsda = 1;
-      }
-
-  htab_delete (ar_hash);
-
-  /* Next: assign dispatch values.  In dwarf2 terms, this would be the
-     landing pad label for the region.  For sjlj though, there is one
-     common landing pad from which we dispatch to the post-landing pads.
-
-     A region receives a dispatch index if it is directly reachable
-     and requires in-function processing.  Regions that share post-landing
-     pads may share dispatch indices.  */
-  /* ??? Post-landing pad sharing doesn't actually happen at the moment
-     (see build_post_landing_pads) so we don't bother checking for it.  */
-
-  index = 0;
-  for (i = cfun->eh->last_region_number; i > 0; --i)
-    if (lp_info[i].directly_reachable)
-      lp_info[i].dispatch_index = index++;
-
-  /* Finally: assign call-site values.  If dwarf2 terms, this would be
-     the region number assigned by convert_to_eh_region_ranges, but
-     handles no-action and must-not-throw differently.  */
-
-  call_site_base = 1;
-  for (i = cfun->eh->last_region_number; i > 0; --i)
-    if (lp_info[i].directly_reachable)
-      {
-       int action = lp_info[i].action_index;
 
+       /* Next: assign call-site values.  If dwarf2 terms, this would be
+          the region number assigned by convert_to_eh_region_ranges, but
+          handles no-action and must-not-throw differently.  */
        /* Map must-not-throw to otherwise unused call-site index 0.  */
        if (action == -2)
-         index = 0;
+         call_site = 0;
        /* Map no-action to otherwise unused call-site index -1.  */
        else if (action == -1)
-         index = -1;
+         call_site = -1;
        /* Otherwise, look it up in the table.  */
        else
-         index = add_call_site (GEN_INT (lp_info[i].dispatch_index),
-                                action, 0);
+         call_site = add_call_site (GEN_INT (disp_index), action, 0);
+       VEC_replace (int, sjlj_lp_call_site_index, i, call_site);
 
-       lp_info[i].call_site_index = index;
+       disp_index++;
       }
+
+  htab_delete (ar_hash);
+
+  return disp_index;
 }
 
+/* Emit code to record the current call-site index before every
+   insn that can throw.  */
+
 static void
-sjlj_mark_call_sites (struct sjlj_lp_info *lp_info)
+sjlj_mark_call_sites (void)
 {
   int last_call_site = -2;
   rtx insn, mem;
 
   for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
     {
-      struct eh_region_d *region;
+      eh_landing_pad lp;
+      eh_region r;
+      bool nothrow;
       int this_call_site;
-      rtx note, before, p;
+      rtx before, p;
 
       /* Reset value tracking at extended basic block boundaries.  */
       if (LABEL_P (insn))
@@ -2368,31 +1070,23 @@ sjlj_mark_call_sites (struct sjlj_lp_info *lp_info)
       if (! INSN_P (insn))
        continue;
 
-      note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
-
-      /* Calls that are known to not throw need not be marked.  */
-      if (note && INTVAL (XEXP (note, 0)) <= 0)
+      nothrow = get_eh_region_and_lp_from_rtx (insn, &r, &lp);
+      if (nothrow)
        continue;
-
-      if (note)
-       region = VEC_index (eh_region, cfun->eh->region_array, INTVAL (XEXP (note, 0)));
-      else
-        region = NULL;
-
-      if (!region)
+      if (lp)
+       this_call_site = VEC_index (int, sjlj_lp_call_site_index, lp->index);
+      else if (r == NULL)
        {
          /* Calls (and trapping insns) without notes are outside any
             exception handling region in this function.  Mark them as
             no action.  */
-         if (CALL_P (insn)
-             || (flag_non_call_exceptions
-                 && may_trap_p (PATTERN (insn))))
-           this_call_site = -1;
-         else
-           continue;
+         this_call_site = -1;
        }
       else
-       this_call_site = lp_info[region->region_number].call_site_index;
+       {
+         gcc_assert (r->type == ERT_MUST_NOT_THROW);
+         this_call_site = 0;
+       }
 
       if (this_call_site == last_call_site)
        continue;
@@ -2525,15 +1219,18 @@ sjlj_emit_function_exit (void)
 }
 
 static void
-sjlj_emit_dispatch_table (rtx dispatch_label, struct sjlj_lp_info *lp_info)
+sjlj_emit_dispatch_table (rtx dispatch_label, int num_dispatch)
 {
   enum machine_mode unwind_word_mode = targetm.unwind_word_mode ();
   enum machine_mode filter_mode = targetm.eh_return_filter_mode ();
-  int i, first_reachable;
-  rtx mem, dispatch, seq, fc;
-  rtx before;
+  eh_landing_pad lp;
+  rtx mem, seq, fc, before, exc_ptr_reg, filter_reg;
+  rtx first_reachable_label;
   basic_block bb;
+  eh_region r;
   edge e;
+  int i, disp_index;
+  gimple switch_stmt;
 
   fc = crtl->eh.sjlj_fc;
 
@@ -2543,14 +1240,18 @@ sjlj_emit_dispatch_table (rtx dispatch_label, struct sjlj_lp_info *lp_info)
 
 #ifndef DONT_USE_BUILTIN_SETJMP
   expand_builtin_setjmp_receiver (dispatch_label);
-#endif
 
-  /* Load up dispatch index, exc_ptr and filter values from the
-     function context.  */
-  mem = adjust_address (fc, TYPE_MODE (integer_type_node),
-                       sjlj_fc_call_site_ofs);
-  dispatch = copy_to_reg (mem);
+  /* The caller of expand_builtin_setjmp_receiver is responsible for
+     making sure that the label doesn't vanish.  The only other caller
+     is the expander for __builtin_setjmp_receiver, which places this
+     label on the nonlocal_goto_label list.  Since we're modeling these
+     CFG edges more exactly, we can use the forced_labels list instead.  */
+  LABEL_PRESERVE_P (dispatch_label) = 1;
+  forced_labels
+    = gen_rtx_EXPR_LIST (VOIDmode, dispatch_label, forced_labels);
+#endif
 
+  /* Load up exc_ptr and filter values from the function context.  */
   mem = adjust_address (fc, unwind_word_mode, sjlj_fc_data_ofs);
   if (unwind_word_mode != ptr_mode)
     {
@@ -2560,58 +1261,110 @@ sjlj_emit_dispatch_table (rtx dispatch_label, struct sjlj_lp_info *lp_info)
       mem = convert_to_mode (ptr_mode, mem, 0);
 #endif
     }
-  emit_move_insn (crtl->eh.exc_ptr, mem);
+  exc_ptr_reg = force_reg (ptr_mode, mem);
 
   mem = adjust_address (fc, unwind_word_mode,
                        sjlj_fc_data_ofs + GET_MODE_SIZE (unwind_word_mode));
   if (unwind_word_mode != filter_mode)
     mem = convert_to_mode (filter_mode, mem, 0);
-  emit_move_insn (crtl->eh.filter, mem);
+  filter_reg = force_reg (filter_mode, mem);
 
   /* Jump to one of the directly reachable regions.  */
-  /* ??? This really ought to be using a switch statement.  */
 
-  first_reachable = 0;
-  for (i = cfun->eh->last_region_number; i > 0; --i)
+  disp_index = 0;
+  first_reachable_label = NULL;
+
+  /* If there's exactly one call site in the function, don't bother
+     generating a switch statement.  */
+  switch_stmt = NULL;
+  if (num_dispatch > 1)
     {
-      if (! lp_info[i].directly_reachable)
-       continue;
+      tree disp;
 
-      if (! first_reachable)
-       {
-         first_reachable = i;
-         continue;
-       }
+      mem = adjust_address (fc, TYPE_MODE (integer_type_node),
+                           sjlj_fc_call_site_ofs);
+      disp = make_tree (integer_type_node, mem);
+
+      switch_stmt = gimple_build_switch_nlabels (num_dispatch, disp, NULL);
+    }
+
+  for (i = 1; VEC_iterate (eh_landing_pad, cfun->eh->lp_array, i, lp); ++i)
+    if (lp && lp->post_landing_pad)
+      {
+       rtx seq2, label;
+
+       start_sequence ();
+
+       lp->landing_pad = dispatch_label;
+
+       if (num_dispatch > 1)
+         {
+           tree t_label, case_elt;
+
+           t_label = create_artificial_label (UNKNOWN_LOCATION);
+           case_elt = build3 (CASE_LABEL_EXPR, void_type_node,
+                              build_int_cst (NULL, disp_index),
+                              NULL, t_label);
+           gimple_switch_set_label (switch_stmt, disp_index, case_elt);
+
+           label = label_rtx (t_label);
+         }
+       else
+         label = gen_label_rtx ();
+
+       if (disp_index == 0)
+         first_reachable_label = label;
+       emit_label (label);
+
+       r = lp->region;
+       if (r->exc_ptr_reg)
+         emit_move_insn (r->exc_ptr_reg, exc_ptr_reg);
+       if (r->filter_reg)
+         emit_move_insn (r->filter_reg, filter_reg);
+
+       seq2 = get_insns ();
+       end_sequence ();
+
+       before = label_rtx (lp->post_landing_pad);
+       bb = emit_to_new_bb_before (seq2, before);
+       e = make_edge (bb, bb->next_bb, EDGE_FALLTHRU);
+       e->count = bb->count;
+       e->probability = REG_BR_PROB_BASE;
 
-      emit_cmp_and_jump_insns (dispatch, GEN_INT (lp_info[i].dispatch_index),
-                              EQ, NULL_RTX, TYPE_MODE (integer_type_node), 0,
-                              (((struct eh_region_d *)
-                                VEC_index (eh_region,
-                                           cfun->eh->region_array, i))
-                               ->post_landing_pad));
+       disp_index++;
+      }
+  gcc_assert (disp_index == num_dispatch);
+
+  if (num_dispatch > 1)
+    {
+      expand_case (switch_stmt);
+      expand_builtin_trap ();
     }
 
   seq = get_insns ();
   end_sequence ();
 
-  before = (((struct eh_region_d *)
-            VEC_index (eh_region, cfun->eh->region_array, first_reachable))
-           ->post_landing_pad);
-
-  bb = emit_to_new_bb_before (seq, before);
-  e = make_edge (bb, bb->next_bb, EDGE_FALLTHRU);
-  e->count = bb->count;
-  e->probability = REG_BR_PROB_BASE;
+  bb = emit_to_new_bb_before (seq, first_reachable_label);
+  if (num_dispatch == 1)
+    {
+      e = make_edge (bb, bb->next_bb, EDGE_FALLTHRU);
+      e->count = bb->count;
+      e->probability = REG_BR_PROB_BASE;
+    }
 }
 
 static void
 sjlj_build_landing_pads (void)
 {
-  struct sjlj_lp_info *lp_info;
+  int num_dispatch;
 
-  lp_info = XCNEWVEC (struct sjlj_lp_info, cfun->eh->last_region_number + 1);
+  num_dispatch = VEC_length (eh_landing_pad, cfun->eh->lp_array);
+  if (num_dispatch == 0)
+    return;
+  VEC_safe_grow (int, heap, sjlj_lp_call_site_index, num_dispatch);
 
-  if (sjlj_find_directly_reachable_regions (lp_info))
+  num_dispatch = sjlj_assign_call_site_values ();
+  if (num_dispatch > 0)
     {
       rtx dispatch_label = gen_label_rtx ();
       int align = STACK_SLOT_ALIGNMENT (sjlj_fc_type_node,
@@ -2622,15 +1375,13 @@ sjlj_build_landing_pads (void)
                              int_size_in_bytes (sjlj_fc_type_node),
                              align);
 
-      sjlj_assign_call_site_values (dispatch_label, lp_info);
-      sjlj_mark_call_sites (lp_info);
-
+      sjlj_mark_call_sites ();
       sjlj_emit_function_enter (dispatch_label);
-      sjlj_emit_dispatch_table (dispatch_label, lp_info);
+      sjlj_emit_dispatch_table (dispatch_label, num_dispatch);
       sjlj_emit_function_exit ();
     }
 
-  free (lp_info);
+  VEC_free (int, heap, sjlj_lp_call_site_index);
 }
 
 /* After initial rtl generation, call back to finish generating
@@ -2641,700 +1392,405 @@ finish_eh_generation (void)
 {
   basic_block bb;
 
-  /* Nothing to do if no regions created.  */
-  if (cfun->eh->region_tree == NULL)
-    return;
-
-  /* The object here is to provide detailed information (via
-     reachable_handlers) on how exception control flows within the
-     function for the CFG construction.  In this first pass, we can
-     include type information garnered from ERT_THROW and
-     ERT_ALLOWED_EXCEPTIONS regions, and hope that it will be useful
-     in deleting unreachable handlers.  Subsequently, we will generate
-     landing pads which will connect many of the handlers, and then
-     type information will not be effective.  Still, this is a win
-     over previous implementations.  */
-
-  /* These registers are used by the landing pads.  Make sure they
-     have been generated.  */
-  get_exception_pointer ();
-  get_exception_filter ();
-
   /* Construct the landing pads.  */
-
-  assign_filter_values ();
-  build_post_landing_pads ();
-  connect_post_landing_pads ();
   if (USING_SJLJ_EXCEPTIONS)
     sjlj_build_landing_pads ();
   else
     dw2_build_landing_pads ();
-
-  crtl->eh.built_landing_pads = 1;
-
-  /* We've totally changed the CFG.  Start over.  */
-  find_exception_handler_labels ();
   break_superblocks ();
+
   if (USING_SJLJ_EXCEPTIONS
       /* Kludge for Alpha/Tru64 (see alpha_gp_save_rtx).  */
       || single_succ_edge (ENTRY_BLOCK_PTR)->insns.r)
     commit_edge_insertions ();
+
+  /* Redirect all EH edges from the post_landing_pad to the landing pad.  */
   FOR_EACH_BB (bb)
     {
-      edge e;
+      eh_landing_pad lp;
       edge_iterator ei;
-      bool eh = false;
-      for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); )
-       {
-         if (e->flags & EDGE_EH)
-           {
-             remove_edge (e);
-             eh = true;
-           }
-         else
-           ei_next (&ei);
-       }
-      if (eh)
-       rtl_make_eh_edge (NULL, bb, BB_END (bb));
-    }
-}
-\f
-/* This section handles removing dead code for flow.  */
-
-/* Splice REGION from the region tree and replace it by REPLACE etc.
-   When UPDATE_CATCH_TRY is true mind updating links from catch to try
-   region.*/
-
-static void
-remove_eh_handler_and_replace (struct eh_region_d *region,
-                              struct eh_region_d *replace,
-                              bool update_catch_try)
-{
-  struct eh_region_d **pp, **pp_start, *p, *outer, *inner;
-  rtx lab;
-
-  outer = region->outer;
+      edge e;
 
-  /* 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 a
-     list of alternate numbers by which we are known.  */
+      lp = get_eh_landing_pad_from_rtx (BB_END (bb));
 
-  VEC_replace (eh_region, cfun->eh->region_array, region->region_number,
-              replace);
-  if (region->aka)
-    {
-      unsigned i;
-      bitmap_iterator bi;
+      FOR_EACH_EDGE (e, ei, bb->succs)
+       if (e->flags & EDGE_EH)
+         break;
 
-      EXECUTE_IF_SET_IN_BITMAP (region->aka, 0, i, bi)
+      /* We should not have generated any new throwing insns during this
+        pass, and we should not have lost any EH edges, so we only need
+        to handle two cases here:
+        (1) reachable handler and an existing edge to post-landing-pad,
+        (2) no reachable handler and no edge.  */
+      gcc_assert ((lp != NULL) == (e != NULL));
+      if (lp != NULL)
        {
-          VEC_replace (eh_region, cfun->eh->region_array, i, replace);
-       }
-    }
-
-  if (replace)
-    {
-      if (!replace->aka)
-        replace->aka = BITMAP_GGC_ALLOC ();
-      if (region->aka)
-       bitmap_ior_into (replace->aka, region->aka);
-      bitmap_set_bit (replace->aka, region->region_number);
-    }
-
-  if (crtl->eh.built_landing_pads)
-    lab = region->landing_pad;
-  else
-    lab = region->label;
-  if (outer)
-    pp_start = &outer->inner;
-  else
-    pp_start = &cfun->eh->region_tree;
-  for (pp = pp_start, p = *pp; p != region; pp = &p->next_peer, p = *pp)
-    continue;
-  *pp = region->next_peer;
-
-  if (replace)
-    pp_start = &replace->inner;
-  else
-    pp_start = &cfun->eh->region_tree;
-  inner = region->inner;
-  if (inner)
-    {
-      for (p = inner; p->next_peer ; p = p->next_peer)
-       p->outer = replace;
-      p->outer = replace;
-
-      p->next_peer = *pp_start;
-      *pp_start = inner;
-    }
-
-  if (region->type == ERT_CATCH
-      && update_catch_try)
-    {
-      struct eh_region_d *eh_try, *next, *prev;
-
-      for (eh_try = region->next_peer;
-          eh_try->type == ERT_CATCH;
-          eh_try = eh_try->next_peer)
-       continue;
-      gcc_assert (eh_try->type == ERT_TRY);
-
-      next = region->u.eh_catch.next_catch;
-      prev = region->u.eh_catch.prev_catch;
+         gcc_assert (BB_HEAD (e->dest) == label_rtx (lp->post_landing_pad));
 
-      if (next)
-       next->u.eh_catch.prev_catch = prev;
-      else
-       eh_try->u.eh_try.last_catch = prev;
-      if (prev)
-       prev->u.eh_catch.next_catch = next;
-      else
-       {
-         eh_try->u.eh_try.eh_catch = next;
-         if (! next)
-           remove_eh_handler (eh_try);
+         redirect_edge_succ (e, BLOCK_FOR_INSN (lp->landing_pad));
+         e->flags |= (CALL_P (BB_END (bb))
+                      ? EDGE_ABNORMAL | EDGE_ABNORMAL_CALL
+                      : EDGE_ABNORMAL);
        }
     }
 }
 
-/* Splice REGION from the region tree and replace it by the outer region
-   etc.  */
+static bool
+gate_handle_eh (void)
+{
+  /* Nothing to do if no regions created.  */
+  return cfun->eh->region_tree != NULL;
+}
 
-static void
-remove_eh_handler (struct eh_region_d *region)
+/* Complete generation of exception handling code.  */
+static unsigned int
+rest_of_handle_eh (void)
 {
-  remove_eh_handler_and_replace (region, region->outer, true);
+  finish_eh_generation ();
+  cleanup_cfg (CLEANUP_NO_INSN_DEL);
+  return 0;
 }
 
-/* Remove Eh region R that has turned out to have no code in its handler.  */
+struct rtl_opt_pass pass_rtl_eh =
+{
+ {
+  RTL_PASS,
+  "eh",                                 /* name */
+  gate_handle_eh,                       /* gate */
+  rest_of_handle_eh,                   /* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_JUMP,                              /* tv_id */
+  0,                                    /* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  TODO_dump_func                        /* todo_flags_finish */
+ }
+};
+\f
+/* This section handles removing dead code for flow.  */
 
 void
-remove_eh_region (int r)
+remove_eh_landing_pad (eh_landing_pad lp)
 {
-  struct eh_region_d *region;
+  eh_landing_pad *pp;
 
-  region = VEC_index (eh_region, cfun->eh->region_array, r);
-  remove_eh_handler (region);
+  for (pp = &lp->region->landing_pads; *pp != lp; pp = &(*pp)->next_lp)
+    continue;
+  *pp = lp->next_lp;
+  
+  if (lp->post_landing_pad)
+    EH_LANDING_PAD_NR (lp->post_landing_pad) = 0;
+  VEC_replace (eh_landing_pad, cfun->eh->lp_array, lp->index, NULL);
 }
 
-/* Remove Eh region R that has turned out to have no code in its handler
-   and replace in by R2.  */
+/* Splice REGION from the region tree.  */
 
 void
-remove_eh_region_and_replace_by_outer_of (int r, int r2)
+remove_eh_handler (eh_region region)
 {
-  struct eh_region_d *region, *region2;
-
-  region = VEC_index (eh_region, cfun->eh->region_array, r);
-  region2 = VEC_index (eh_region, cfun->eh->region_array, r2);
-  remove_eh_handler_and_replace (region, region2->outer, true);
-}
+  eh_region *pp, *pp_start, p, outer;
+  eh_landing_pad lp;
 
-/* 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 (void (*callback) (rtx))
-{
-  int i;
-  for (i = 0; i < cfun->eh->last_region_number; i++)
+  for (lp = region->landing_pads; lp ; lp = lp->next_lp)
     {
-      struct eh_region_d *r = VEC_index (eh_region, cfun->eh->region_array, i);
-      if (r && r->region_number == i && r->label
-          && LABEL_P (r->label))
-       (*callback) (r->label);
+      if (lp->post_landing_pad)
+       EH_LANDING_PAD_NR (lp->post_landing_pad) = 0;
+      VEC_replace (eh_landing_pad, cfun->eh->lp_array, lp->index, NULL);
     }
-}
 
-/* Invoke CALLBACK for every exception region in the current function.  */
-
-void
-for_each_eh_region (void (*callback) (struct eh_region_d *))
-{
-  int i, n = cfun->eh->last_region_number;
-  for (i = 1; i <= n; ++i)
+  outer = region->outer;
+  if (outer)
+    pp_start = &outer->inner;
+  else
+    pp_start = &cfun->eh->region_tree;
+  for (pp = pp_start, p = *pp; p != region; pp = &p->next_peer, p = *pp)
+    continue;
+  if (region->inner)
     {
-      struct eh_region_d *region;
-
-      region = VEC_index (eh_region, cfun->eh->region_array, i);
-      if (region)
-       (*callback) (region);
+      *pp = p = region->inner;
+      do
+       {
+         p->outer = outer;
+         pp = &p->next_peer;
+         p = *pp;
+       }
+      while (p);
     }
-}
-\f
-/* This section describes CFG exception edges for flow.  */
+  *pp = region->next_peer;
 
-/* For communicating between calls to reachable_next_level.  */
-struct reachable_info
-{
-  tree types_caught;
-  tree types_allowed;
-  void (*callback) (struct eh_region_d *, void *);
-  void *callback_data;
-};
+  VEC_replace (eh_region, cfun->eh->region_array, region->index, NULL);
+}
 
-/* A subroutine of reachable_next_level.  Return true if TYPE, or a
-   base class of TYPE, is in HANDLED.  */
+/* Invokes CALLBACK for every exception handler landing pad label.
+   Only used by reload hackery; should not be used by new code.  */
 
-static int
-check_handled (tree handled, tree type)
+void
+for_each_eh_label (void (*callback) (rtx))
 {
-  tree t;
+  eh_landing_pad lp;
+  int i;
 
-  /* We can check for exact matches without front-end help.  */
-  if (! lang_eh_type_covers)
+  for (i = 1; VEC_iterate (eh_landing_pad, cfun->eh->lp_array, i, lp); ++i)
     {
-      for (t = handled; t ; t = TREE_CHAIN (t))
+      if (lp)
        {
-         tree t1 = TREE_VALUE (t);
-         tree t2 = type;
-
-         /* If the types have been converted to runtime types (i.e.,
-            when the IL is being read from disk in an LTO
-            compilation), then T1 and T2 will be pointers to the
-            runtime type of the form '(void *) &<runtime_type>' (See
-            cp/except.c:build_eh_type_type).  Strip the conversion
-            and the address.  */
-         if (CONVERT_EXPR_P (t1))
-           {
-             STRIP_NOPS (t1);
-             gcc_assert (TREE_CODE (t1) == ADDR_EXPR);
-             t1 = TREE_OPERAND (t1, 0);
-           }
-
-         if (CONVERT_EXPR_P (t2))
-           {
-             STRIP_NOPS (t2);
-             gcc_assert (TREE_CODE (t2) == ADDR_EXPR);
-             t2 = TREE_OPERAND (t2, 0);
-           }
-
-         if (t1 == t2)
-           return 1;
+         rtx lab = lp->landing_pad;
+         if (lab && LABEL_P (lab))
+           (*callback) (lab);
        }
     }
-  else
-    {
-      for (t = handled; t ; t = TREE_CHAIN (t))
-       if ((*lang_eh_type_covers) (TREE_VALUE (t), type))
-         return 1;
-    }
-
-  return 0;
 }
+\f
+/* Create the REG_EH_REGION note for INSN, given its ECF_FLAGS for a
+   call insn. 
+
+   At the gimple level, we use LP_NR
+       > 0 : The statement transfers to landing pad LP_NR
+       = 0 : The statement is outside any EH region
+       < 0 : The statement is within MUST_NOT_THROW region -LP_NR.
+
+   At the rtl level, we use LP_NR
+       > 0 : The insn transfers to landing pad LP_NR
+       = 0 : The insn cannot throw
+       < 0 : The insn is within MUST_NOT_THROW region -LP_NR
+       = INT_MIN : The insn cannot throw or execute a nonlocal-goto.
+       missing note: The insn is outside any EH region.
+
+  ??? This difference probably ought to be avoided.  We could stand
+  to record nothrow for arbitrary gimple statements, and so avoid
+  some moderately complex lookups in stmt_could_throw_p.  Perhaps
+  NOTHROW should be mapped on both sides to INT_MIN.  Perhaps the
+  no-nonlocal-goto property should be recorded elsewhere as a bit
+  on the call_insn directly.  Perhaps we should make more use of
+  attaching the trees to call_insns (reachable via symbol_ref in
+  direct call cases) and just pull the data out of the trees.  */
 
-/* A subroutine of reachable_next_level.  If we are collecting a list
-   of handlers, add one.  After landing pad generation, reference
-   it instead of the handlers themselves.  Further, the handlers are
-   all wired together, so by referencing one, we've got them all.
-   Before landing pad generation we reference each handler individually.
-
-   LP_REGION contains the landing pad; REGION is the handler.  */
-
-static void
-add_reachable_handler (struct reachable_info *info,
-                      struct eh_region_d *lp_region,
-                      struct eh_region_d *region)
+void
+make_reg_eh_region_note (rtx insn, int ecf_flags, int lp_nr)
 {
-  if (! info)
-    return;
-
-  if (crtl->eh.built_landing_pads)
-    info->callback (lp_region, info->callback_data);
+  rtx value;
+  if (ecf_flags & ECF_NOTHROW)
+    value = const0_rtx;
+  else if (lp_nr != 0)
+    value = GEN_INT (lp_nr);
   else
-    info->callback (region, info->callback_data);
+    return;
+  add_reg_note (insn, REG_EH_REGION, value);
 }
 
-/* Process one level of exception regions for reachability.
-   If TYPE_THROWN is non-null, then it is the *exact* type being
-   propagated.  If INFO is non-null, then collect handler labels
-   and caught/allowed type information between invocations.  */
+/* Create a REG_EH_REGION note for a CALL_INSN that cannot throw
+   nor perform a non-local goto.  Replace the region note if it
+   already exists.  */
 
-static enum reachable_code
-reachable_next_level (struct eh_region_d *region, tree type_thrown,
-                     struct reachable_info *info,
-                     bool maybe_resx)
+void
+make_reg_eh_region_note_nothrow_nononlocal (rtx insn)
 {
-  switch (region->type)
-    {
-    case ERT_CLEANUP:
-      /* Before landing-pad generation, we model control flow
-        directly to the individual handlers.  In this way we can
-        see that catch handler types may shadow one another.  */
-      add_reachable_handler (info, region, region);
-      return RNL_MAYBE_CAUGHT;
+  rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
+  rtx intmin = GEN_INT (INT_MIN);
 
-    case ERT_TRY:
-      {
-       struct eh_region_d *c;
-       enum reachable_code ret = RNL_NOT_CAUGHT;
-
-       for (c = region->u.eh_try.eh_catch; c ; c = c->u.eh_catch.next_catch)
-         {
-           /* A catch-all handler ends the search.  */
-           if (c->u.eh_catch.type_list == NULL)
-             {
-               add_reachable_handler (info, region, c);
-               return RNL_CAUGHT;
-             }
-
-           if (type_thrown)
-             {
-               /* If we have at least one type match, end the search.  */
-               tree tp_node = c->u.eh_catch.type_list;
-
-               for (; tp_node; tp_node = TREE_CHAIN (tp_node))
-                 {
-                   tree type = TREE_VALUE (tp_node);
-
-                   if (type == type_thrown
-                       || (lang_eh_type_covers
-                           && (*lang_eh_type_covers) (type, type_thrown)))
-                     {
-                       add_reachable_handler (info, region, c);
-                       return RNL_CAUGHT;
-                     }
-                 }
-
-               /* If we have definitive information of a match failure,
-                  the catch won't trigger.  */
-               if (lang_eh_type_covers)
-                 return RNL_NOT_CAUGHT;
-             }
-
-           /* At this point, we either don't know what type is thrown or
-              don't have front-end assistance to help deciding if it is
-              covered by one of the types in the list for this region.
-
-              We'd then like to add this region to the list of reachable
-              handlers since it is indeed potentially reachable based on the
-              information we have.
-
-              Actually, this handler is for sure not reachable if all the
-              types it matches have already been caught. That is, it is only
-              potentially reachable if at least one of the types it catches
-              has not been previously caught.  */
-
-           if (! info)
-             ret = RNL_MAYBE_CAUGHT;
-           else
-             {
-               tree tp_node = c->u.eh_catch.type_list;
-               bool maybe_reachable = false;
-
-               /* Compute the potential reachability of this handler and
-                  update the list of types caught at the same time.  */
-               for (; tp_node; tp_node = TREE_CHAIN (tp_node))
-                 {
-                   tree type = TREE_VALUE (tp_node);
-
-                   if (! check_handled (info->types_caught, type))
-                     {
-                       info->types_caught
-                         = tree_cons (NULL, type, info->types_caught);
-
-                       maybe_reachable = true;
-                     }
-                 }
-
-               if (maybe_reachable)
-                 {
-                   add_reachable_handler (info, region, c);
-
-                   /* ??? If the catch type is a base class of every allowed
-                      type, then we know we can stop the search.  */
-                   ret = RNL_MAYBE_CAUGHT;
-                 }
-             }
-         }
-
-       return ret;
-      }
-
-    case ERT_ALLOWED_EXCEPTIONS:
-      /* An empty list of types definitely ends the search.  */
-      if (region->u.allowed.type_list == NULL_TREE)
-       {
-         add_reachable_handler (info, region, region);
-         return RNL_CAUGHT;
-       }
-
-      /* Collect a list of lists of allowed types for use in detecting
-        when a catch may be transformed into a catch-all.  */
-      if (info)
-       info->types_allowed = tree_cons (NULL_TREE,
-                                        region->u.allowed.type_list,
-                                        info->types_allowed);
-
-      /* If we have definitive information about the type hierarchy,
-        then we can tell if the thrown type will pass through the
-        filter.  */
-      if (type_thrown && lang_eh_type_covers)
-       {
-         if (check_handled (region->u.allowed.type_list, type_thrown))
-           return RNL_NOT_CAUGHT;
-         else
-           {
-             add_reachable_handler (info, region, region);
-             return RNL_CAUGHT;
-           }
-       }
-
-      add_reachable_handler (info, region, region);
-      return RNL_MAYBE_CAUGHT;
+  if (note != 0)
+    XEXP (note, 0) = intmin;
+  else
+    add_reg_note (insn, REG_EH_REGION, intmin);
+}
 
-    case ERT_CATCH:
-      /* Catch regions are handled by their controlling try region.  */
-      return RNL_NOT_CAUGHT;
+/* Return true if INSN could throw, assuming no REG_EH_REGION note
+   to the contrary.  */
 
-    case ERT_MUST_NOT_THROW:
-      /* Here we end our search, since no exceptions may propagate.
-        
-         Local landing pads of ERT_MUST_NOT_THROW instructions are reachable
-        only via locally handled RESX instructions.  
+bool
+insn_could_throw_p (const_rtx insn)
+{
+  if (CALL_P (insn))
+    return true;
+  if (INSN_P (insn) && flag_non_call_exceptions)
+    return may_trap_p (PATTERN (insn));
+  return false;
+}
 
-        When we inline a function call, we can bring in new handlers.  In order
-        to avoid ERT_MUST_NOT_THROW landing pads from being deleted as unreachable
-        assume that such handlers exists prior for any inlinable call prior
-        inlining decisions are fixed.  */
+/* Copy an REG_EH_REGION note to each insn that might throw beginning
+   at FIRST and ending at LAST.  NOTE_OR_INSN is either the source insn
+   to look for a note, or the note itself.  */
 
-      if (maybe_resx)
-       {
-         add_reachable_handler (info, region, region);
-         return RNL_CAUGHT;
-       }
-      else
-       return RNL_BLOCKED;
+void
+copy_reg_eh_region_note_forward (rtx note_or_insn, rtx first, rtx last)
+{
+  rtx insn, note = note_or_insn;
 
-    case ERT_THROW:
-    case ERT_UNKNOWN:
-      /* Shouldn't see these here.  */
-      gcc_unreachable ();
-      break;
-    default:
-      gcc_unreachable ();
+  if (INSN_P (note_or_insn))
+    {
+      note = find_reg_note (note_or_insn, REG_EH_REGION, NULL_RTX);
+      if (note == NULL)
+       return;
     }
+  note = XEXP (note, 0);
+
+  for (insn = first; insn != last ; insn = NEXT_INSN (insn))
+    if (!find_reg_note (insn, REG_EH_REGION, NULL_RTX)
+        && insn_could_throw_p (insn))
+      add_reg_note (insn, REG_EH_REGION, note);
 }
 
-/* Invoke CALLBACK on each region reachable from REGION_NUMBER.  */
+/* Likewise, but iterate backward.  */
 
 void
-foreach_reachable_handler (int region_number, bool is_resx, bool inlinable_call,
-                          void (*callback) (struct eh_region_d *, void *),
-                          void *callback_data)
+copy_reg_eh_region_note_backward (rtx note_or_insn, rtx last, rtx first)
 {
-  struct reachable_info info;
-  struct eh_region_d *region;
-  tree type_thrown;
-
-  memset (&info, 0, sizeof (info));
-  info.callback = callback;
-  info.callback_data = callback_data;
-
-  region = VEC_index (eh_region, cfun->eh->region_array, region_number);
-  if (!region)
-    return;
+  rtx insn, note = note_or_insn;
 
-  type_thrown = NULL_TREE;
-  if (is_resx)
+  if (INSN_P (note_or_insn))
     {
-      /* A RESX leaves a region instead of entering it.  Thus the
-        region itself may have been deleted out from under us.  */
-      if (region == NULL)
+      note = find_reg_note (note_or_insn, REG_EH_REGION, NULL_RTX);
+      if (note == NULL)
        return;
-      region = region->outer;
-    }
-  else if (region->type == ERT_THROW)
-    {
-      type_thrown = region->u.eh_throw.type;
-      region = region->outer;
     }
+  note = XEXP (note, 0);
 
-  while (region)
-    {
-      if (reachable_next_level (region, type_thrown, &info,
-                               inlinable_call || is_resx) >= RNL_CAUGHT)
-       break;
-      /* If we have processed one cleanup, there is no point in
-        processing any more of them.  Each cleanup will have an edge
-        to the next outer cleanup region, so the flow graph will be
-        accurate.  */
-      if (region->type == ERT_CLEANUP)
-        {
-         enum reachable_code code = RNL_NOT_CAUGHT;
-         region = find_prev_try (region->outer);
-         /* Continue looking for outer TRY region until we find one
-            that might cath something.  */
-          while (region
-                && (code = reachable_next_level (region, type_thrown, &info,
-                                                 inlinable_call || is_resx))
-                    == RNL_NOT_CAUGHT)
-           region = find_prev_try (region->outer);
-         if (code >= RNL_CAUGHT)
-           break;
-       }
-      if (region)
-       region = region->outer;
-    }
+  for (insn = last; insn != first; insn = PREV_INSN (insn))
+    if (insn_could_throw_p (insn))
+      add_reg_note (insn, REG_EH_REGION, note);
 }
 
-/* Retrieve a list of labels of exception handlers which can be
-   reached by a given insn.  */
 
-static void
-arh_to_landing_pad (struct eh_region_d *region, void *data)
-{
-  rtx *p_handlers = (rtx *) data;
-  if (! *p_handlers)
-    *p_handlers = alloc_INSN_LIST (region->landing_pad, NULL_RTX);
-}
+/* Extract all EH information from INSN.  Return true if the insn
+   was marked NOTHROW.  */
 
-static void
-arh_to_label (struct eh_region_d *region, void *data)
+static bool
+get_eh_region_and_lp_from_rtx (const_rtx insn, eh_region *pr,
+                              eh_landing_pad *plp)
 {
-  rtx *p_handlers = (rtx *) data;
-  *p_handlers = alloc_INSN_LIST (region->label, *p_handlers);
-}
+  eh_landing_pad lp = NULL;
+  eh_region r = NULL;
+  bool ret = false;
+  rtx note;
+  int lp_nr;
 
-rtx
-reachable_handlers (rtx insn)
-{
-  bool is_resx = false;
-  rtx handlers = NULL;
-  int region_number;
+  if (! INSN_P (insn))
+    goto egress;
+
+  if (NONJUMP_INSN_P (insn)
+      && GET_CODE (PATTERN (insn)) == SEQUENCE)
+    insn = XVECEXP (PATTERN (insn), 0, 0);
 
-  if (JUMP_P (insn)
-      && GET_CODE (PATTERN (insn)) == RESX)
+  note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
+  if (!note)
     {
-      region_number = XINT (PATTERN (insn), 0);
-      is_resx = true;
+      ret = !insn_could_throw_p (insn);
+      goto egress;
     }
-  else
+
+  lp_nr = INTVAL (XEXP (note, 0));
+  if (lp_nr == 0 || lp_nr == INT_MIN)
     {
-      rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
-      if (!note || INTVAL (XEXP (note, 0)) <= 0)
-       return NULL;
-      region_number = INTVAL (XEXP (note, 0));
+      ret = true;
+      goto egress;
     }
 
-  foreach_reachable_handler (region_number, is_resx, false,
-                            (crtl->eh.built_landing_pads
-                             ? arh_to_landing_pad
-                             : arh_to_label),
-                            &handlers);
+  if (lp_nr < 0)
+    r = VEC_index (eh_region, cfun->eh->region_array, -lp_nr);
+  else
+    {
+      lp = VEC_index (eh_landing_pad, cfun->eh->lp_array, lp_nr);
+      r = lp->region;
+    }
 
-  return handlers;
+ egress:
+  *plp = lp;
+  *pr = r;
+  return ret;
 }
 
-/* Determine if the given INSN can throw an exception that is caught
-   within the function.  */
+/* Return the landing pad to which INSN may go, or NULL if it does not
+   have a reachable landing pad within this function.  */
 
-bool
-can_throw_internal_1 (int region_number, bool is_resx, bool inlinable_call)
+eh_landing_pad
+get_eh_landing_pad_from_rtx (const_rtx insn)
 {
-  struct eh_region_d *region;
-  tree type_thrown;
+  eh_landing_pad lp;
+  eh_region r;
 
-  region = VEC_index (eh_region, cfun->eh->region_array, region_number);
-  if (!region)
-    return false;
+  get_eh_region_and_lp_from_rtx (insn, &r, &lp);
+  return lp;
+}
 
-  type_thrown = NULL_TREE;
-  if (is_resx)
-    region = region->outer;
-  else if (region->type == ERT_THROW)
-    {
-      type_thrown = region->u.eh_throw.type;
-      region = region->outer;
-    }
+/* Return the region to which INSN may go, or NULL if it does not
+   have a reachable region within this function.  */
 
-  /* If this exception is ignored by each and every containing region,
-     then control passes straight out.  The runtime may handle some
-     regions, which also do not require processing internally.  */
-  for (; region; region = region->outer)
-    {
-      enum reachable_code how = reachable_next_level (region, type_thrown, 0,
-                                                     inlinable_call || is_resx);
-      if (how == RNL_BLOCKED)
-       return false;
-      if (how != RNL_NOT_CAUGHT)
-       return true;
-    }
+eh_region
+get_eh_region_from_rtx (const_rtx insn)
+{
+  eh_landing_pad lp;
+  eh_region r;
 
-  return false;
+  get_eh_region_and_lp_from_rtx (insn, &r, &lp);
+  return r;
 }
 
+/* Return true if INSN throws and is caught by something in this function.  */
+
 bool
 can_throw_internal (const_rtx insn)
 {
-  rtx note;
+  return get_eh_landing_pad_from_rtx (insn) != NULL;
+}
+
+/* Return true if INSN throws and escapes from the current function.  */
+
+bool
+can_throw_external (const_rtx insn)
+{
+  eh_landing_pad lp;
+  eh_region r;
+  bool nothrow;
 
   if (! INSN_P (insn))
     return false;
 
-  if (JUMP_P (insn)
-      && GET_CODE (PATTERN (insn)) == RESX
-      && XINT (PATTERN (insn), 0) > 0)
-    return can_throw_internal_1 (XINT (PATTERN (insn), 0), true, false);
-
   if (NONJUMP_INSN_P (insn)
       && GET_CODE (PATTERN (insn)) == SEQUENCE)
-    insn = XVECEXP (PATTERN (insn), 0, 0);
-
-  /* Every insn that might throw has an EH_REGION note.  */
-  note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
-  if (!note || INTVAL (XEXP (note, 0)) <= 0)
-    return false;
+    {
+      rtx seq = PATTERN (insn);
+      int i, n = XVECLEN (seq, 0);
 
-  return can_throw_internal_1 (INTVAL (XEXP (note, 0)), false, false);
-}
+      for (i = 0; i < n; i++)
+       if (can_throw_external (XVECEXP (seq, 0, i)))
+         return true;
 
-/* Determine if the given INSN can throw an exception that is
-   visible outside the function.  */
+      return false;
+    }
 
-bool
-can_throw_external_1 (int region_number, bool is_resx, bool inlinable_call)
-{
-  struct eh_region_d *region;
-  tree type_thrown;
+  nothrow = get_eh_region_and_lp_from_rtx (insn, &r, &lp);
 
-  region = VEC_index (eh_region, cfun->eh->region_array, region_number);
-  if (!region)
-    return true;
+  /* If we can't throw, we obviously can't throw external.  */
+  if (nothrow)
+    return false;
 
-  type_thrown = NULL_TREE;
-  if (is_resx)
-    region = region->outer;
-  else if (region->type == ERT_THROW)
-    {
-      type_thrown = region->u.eh_throw.type;
-      region = region->outer;
-    }
+  /* If we have an internal landing pad, then we're not external.  */
+  if (lp != NULL)
+    return false;
 
-  /* If the exception is caught or blocked by any containing region,
-     then it is not seen by any calling function.  */
-  for (; region ; region = region->outer)
-    if (reachable_next_level (region, type_thrown, NULL,
-       inlinable_call || is_resx) >= RNL_CAUGHT)
-      return false;
+  /* If we're not within an EH region, then we are external.  */
+  if (r == NULL)
+    return true;
 
-  return true;
+  /* The only thing that ought to be left is MUST_NOT_THROW regions,
+     which don't always have landing pads.  */
+  gcc_assert (r->type == ERT_MUST_NOT_THROW);
+  return false;
 }
 
+/* Return true if INSN cannot throw at all.  */
+
 bool
-can_throw_external (const_rtx insn)
+insn_nothrow_p (const_rtx insn)
 {
-  rtx note;
+  eh_landing_pad lp;
+  eh_region r;
 
   if (! INSN_P (insn))
-    return false;
-
-  if (JUMP_P (insn)
-      && GET_CODE (PATTERN (insn)) == RESX
-      && XINT (PATTERN (insn), 0) > 0)
-    return can_throw_external_1 (XINT (PATTERN (insn), 0), true, false);
+    return true;
 
   if (NONJUMP_INSN_P (insn)
       && GET_CODE (PATTERN (insn)) == SEQUENCE)
@@ -3343,30 +1799,30 @@ can_throw_external (const_rtx insn)
       int i, n = XVECLEN (seq, 0);
 
       for (i = 0; i < n; i++)
-       if (can_throw_external (XVECEXP (seq, 0, i)))
-         return true;
+       if (!insn_nothrow_p (XVECEXP (seq, 0, i)))
+         return false;
 
-      return false;
+      return true;
     }
 
-  note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
-  if (!note)
+  return get_eh_region_and_lp_from_rtx (insn, &r, &lp);
+}
+
+/* Return true if INSN can perform a non-local goto.  */
+/* ??? This test is here in this file because it (ab)uses REG_EH_REGION.  */
+
+bool
+can_nonlocal_goto (const_rtx insn)
+{
+  if (nonlocal_goto_handler_labels && CALL_P (insn))
     {
-      /* Calls (and trapping insns) without notes are outside any
-        exception handling region in this function.  We have to
-        assume it might throw.  Given that the front end and middle
-        ends mark known NOTHROW functions, this isn't so wildly
-        inaccurate.  */
-      return (CALL_P (insn)
-             || (flag_non_call_exceptions
-                 && may_trap_p (PATTERN (insn))));
+      rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
+      if (!note || INTVAL (XEXP (note, 0)) != INT_MIN)
+       return true;
     }
-  if (INTVAL (XEXP (note, 0)) <= 0)
-    return false;
-
-  return can_throw_external_1 (INTVAL (XEXP (note, 0)), false, false);
+  return false;
 }
-
+\f
 /* Set TREE_NOTHROW and crtl->all_throwers_are_sibcalls.  */
 
 unsigned int
@@ -3454,8 +1910,81 @@ struct rtl_opt_pass pass_set_nothrow_function_flags =
  }
 };
 
-\f
-/* Various hooks for unwind library.  */
+\f
+/* Various hooks for unwind library.  */
+
+/* Expand the EH support builtin functions:
+   __builtin_eh_pointer and __builtin_eh_filter.  */
+
+static eh_region
+expand_builtin_eh_common (tree region_nr_t)
+{
+  HOST_WIDE_INT region_nr;
+  eh_region region;
+
+  gcc_assert (host_integerp (region_nr_t, 0));
+  region_nr = tree_low_cst (region_nr_t, 0);
+
+  region = VEC_index (eh_region, cfun->eh->region_array, region_nr);
+
+  /* ??? We shouldn't have been able to delete a eh region without
+     deleting all the code that depended on it.  */
+  gcc_assert (region != NULL);
+
+  return region;
+}
+
+/* Expand to the exc_ptr value from the given eh region.  */
+
+rtx
+expand_builtin_eh_pointer (tree exp)
+{
+  eh_region region
+    = expand_builtin_eh_common (CALL_EXPR_ARG (exp, 0));
+  if (region->exc_ptr_reg == NULL)
+    region->exc_ptr_reg = gen_reg_rtx (ptr_mode);
+  return region->exc_ptr_reg;
+}
+
+/* Expand to the filter value from the given eh region.  */
+
+rtx
+expand_builtin_eh_filter (tree exp)
+{
+  eh_region region
+    = expand_builtin_eh_common (CALL_EXPR_ARG (exp, 0));
+  if (region->filter_reg == NULL)
+    region->filter_reg = gen_reg_rtx (targetm.eh_return_filter_mode ());
+  return region->filter_reg;
+}
+
+/* Copy the exc_ptr and filter values from one landing pad's registers
+   to another.  This is used to inline the resx statement.  */
+
+rtx
+expand_builtin_eh_copy_values (tree exp)
+{
+  eh_region dst
+    = expand_builtin_eh_common (CALL_EXPR_ARG (exp, 0));
+  eh_region src
+    = expand_builtin_eh_common (CALL_EXPR_ARG (exp, 1));
+  enum machine_mode fmode = targetm.eh_return_filter_mode ();
+
+  if (dst->exc_ptr_reg == NULL)
+    dst->exc_ptr_reg = gen_reg_rtx (ptr_mode);
+  if (src->exc_ptr_reg == NULL)
+    src->exc_ptr_reg = gen_reg_rtx (ptr_mode);
+
+  if (dst->filter_reg == NULL)
+    dst->filter_reg = gen_reg_rtx (fmode);
+  if (src->filter_reg == NULL)
+    src->filter_reg = gen_reg_rtx (fmode);
+
+  emit_move_insn (dst->exc_ptr_reg, src->exc_ptr_reg);
+  emit_move_insn (dst->filter_reg, src->filter_reg);
+
+  return const0_rtx;
+}
 
 /* Do any necessary initialization to access arbitrary stack frames.
    On the SPARC, this means flushing the register windows.  */
@@ -3472,6 +2001,10 @@ expand_builtin_unwind_init (void)
 #endif
 }
 
+/* Map a non-negative number to an eh return data register number; expands
+   to -1 if no return data register is associated with the input number.
+   At least the inputs 0 and 1 must be mapped; the target may provide more.  */
+
 rtx
 expand_builtin_eh_return_data_regno (tree exp)
 {
@@ -3580,6 +2113,10 @@ expand_builtin_eh_return (tree stackadj_tree ATTRIBUTE_UNUSED,
   emit_jump (crtl->eh.ehr_label);
 }
 
+/* Expand __builtin_eh_return.  This exit path from the function loads up
+   the eh return data registers, adjusts the stack, and branches to a
+   given PC other than the normal return address.  */
+
 void
 expand_eh_return (void)
 {
@@ -3685,7 +2222,7 @@ add_action_record (htab_t ar_hash, int filter, int next)
   if ((new_ar = *slot) == NULL)
     {
       new_ar = XNEW (struct action_record);
-      new_ar->offset = VARRAY_ACTIVE_SIZE (crtl->eh.action_record_data) + 1;
+      new_ar->offset = VEC_length (uchar, crtl->eh.action_record_data) + 1;
       new_ar->filter = filter;
       new_ar->next = next;
       *slot = new_ar;
@@ -3697,7 +2234,7 @@ add_action_record (htab_t ar_hash, int filter, int next)
 
       push_sleb128 (&crtl->eh.action_record_data, filter);
       if (next)
-       next -= VARRAY_ACTIVE_SIZE (crtl->eh.action_record_data) + 1;
+       next -= VEC_length (uchar, crtl->eh.action_record_data) + 1;
       push_sleb128 (&crtl->eh.action_record_data, next);
     }
 
@@ -3705,9 +2242,8 @@ add_action_record (htab_t ar_hash, int filter, int next)
 }
 
 static int
-collect_one_action_chain (htab_t ar_hash, struct eh_region_d *region)
+collect_one_action_chain (htab_t ar_hash, eh_region region)
 {
-  struct eh_region_d *c;
   int next;
 
   /* If we've reached the top of the region chain, then we have
@@ -3718,67 +2254,72 @@ collect_one_action_chain (htab_t ar_hash, struct eh_region_d *region)
   switch (region->type)
     {
     case ERT_CLEANUP:
-      /* A cleanup adds a zero filter to the beginning of the chain, but
-        there are special cases to look out for.  If there are *only*
-        cleanups along a path, then it compresses to a zero action.
-        Further, if there are multiple cleanups along a path, we only
-        need to represent one of them, as that is enough to trigger
-        entry to the landing pad at runtime.  */
-      next = collect_one_action_chain (ar_hash, region->outer);
-      if (next <= 0)
-       return 0;
-      for (c = region->outer; c ; c = c->outer)
-       if (c->type == ERT_CLEANUP)
-         return next;
-      return add_action_record (ar_hash, 0, next);
+      {
+       eh_region r;
+       /* A cleanup adds a zero filter to the beginning of the chain, but
+          there are special cases to look out for.  If there are *only*
+          cleanups along a path, then it compresses to a zero action.
+          Further, if there are multiple cleanups along a path, we only
+          need to represent one of them, as that is enough to trigger
+          entry to the landing pad at runtime.  */
+       next = collect_one_action_chain (ar_hash, region->outer);
+       if (next <= 0)
+         return 0;
+       for (r = region->outer; r ; r = r->outer)
+         if (r->type == ERT_CLEANUP)
+           return next;
+       return add_action_record (ar_hash, 0, next);
+      }
 
     case ERT_TRY:
-      /* Process the associated catch regions in reverse order.
-        If there's a catch-all handler, then we don't need to
-        search outer regions.  Use a magic -3 value to record
-        that we haven't done the outer search.  */
-      next = -3;
-      for (c = region->u.eh_try.last_catch; c ; c = c->u.eh_catch.prev_catch)
-       {
-         if (c->u.eh_catch.type_list == NULL)
-           {
-             /* Retrieve the filter from the head of the filter list
-                where we have stored it (see assign_filter_values).  */
-             int filter
-               = TREE_INT_CST_LOW (TREE_VALUE (c->u.eh_catch.filter_list));
-
-             next = add_action_record (ar_hash, filter, 0);
-           }
-         else
-           {
-             /* Once the outer search is done, trigger an action record for
-                 each filter we have.  */
-             tree flt_node;
+      {
+       eh_catch c;
+
+       /* Process the associated catch regions in reverse order.
+          If there's a catch-all handler, then we don't need to
+          search outer regions.  Use a magic -3 value to record
+          that we haven't done the outer search.  */
+       next = -3;
+       for (c = region->u.eh_try.last_catch; c ; c = c->prev_catch)
+         {
+           if (c->type_list == NULL)
+             {
+               /* Retrieve the filter from the head of the filter list
+                  where we have stored it (see assign_filter_values).  */
+               int filter = TREE_INT_CST_LOW (TREE_VALUE (c->filter_list));
+               next = add_action_record (ar_hash, filter, 0);
+             }
+           else
+             {
+               /* Once the outer search is done, trigger an action record for
+                  each filter we have.  */
+               tree flt_node;
 
-             if (next == -3)
-               {
-                 next = collect_one_action_chain (ar_hash, region->outer);
-
-                 /* If there is no next action, terminate the chain.  */
-                 if (next == -1)
-                   next = 0;
-                 /* If all outer actions are cleanups or must_not_throw,
-                    we'll have no action record for it, since we had wanted
-                    to encode these states in the call-site record directly.
-                    Add a cleanup action to the chain to catch these.  */
-                 else if (next <= 0)
-                   next = add_action_record (ar_hash, 0, 0);
-               }
+               if (next == -3)
+                 {
+                   next = collect_one_action_chain (ar_hash, region->outer);
+
+                   /* If there is no next action, terminate the chain.  */
+                   if (next == -1)
+                     next = 0;
+                   /* If all outer actions are cleanups or must_not_throw,
+                      we'll have no action record for it, since we had wanted
+                      to encode these states in the call-site record directly.
+                      Add a cleanup action to the chain to catch these.  */
+                   else if (next <= 0)
+                     next = add_action_record (ar_hash, 0, 0);
+                 }
 
-             flt_node = c->u.eh_catch.filter_list;
-             for (; flt_node; flt_node = TREE_CHAIN (flt_node))
-               {
-                 int filter = TREE_INT_CST_LOW (TREE_VALUE (flt_node));
-                 next = add_action_record (ar_hash, filter, next);
-               }
-           }
-       }
-      return next;
+               flt_node = c->filter_list;
+               for (; flt_node; flt_node = TREE_CHAIN (flt_node))
+                 {
+                   int filter = TREE_INT_CST_LOW (TREE_VALUE (flt_node));
+                   next = add_action_record (ar_hash, filter, next);
+                 }
+             }
+         }
+       return next;
+      }
 
     case ERT_ALLOWED_EXCEPTIONS:
       /* An exception specification adds its filter to the
@@ -3803,23 +2344,16 @@ collect_one_action_chain (htab_t ar_hash, struct eh_region_d *region)
         the no handler or cleanup case in that we do require an lsda
         to be generated.  Return a magic -2 value to record this.  */
       return -2;
-
-    case ERT_CATCH:
-    case ERT_THROW:
-      /* CATCH regions are handled in TRY above.  THROW regions are
-        for optimization information only and produce no output.  */
-      return collect_one_action_chain (ar_hash, region->outer);
-
-    default:
-      gcc_unreachable ();
     }
+
+  gcc_unreachable ();
 }
 
 static int
 add_call_site (rtx landing_pad, int action, int section)
 {
   call_site_record record;
-  
+
   record = GGC_NEW (struct call_site_record_d);
   record->landing_pad = landing_pad;
   record->action = action;
@@ -3835,7 +2369,7 @@ add_call_site (rtx landing_pad, int action, int section)
    The new note numbers will not refer to region numbers, but
    instead to call site entries.  */
 
-unsigned int
+static unsigned int
 convert_to_eh_region_ranges (void)
 {
   rtx insn, iter, note;
@@ -3854,17 +2388,16 @@ convert_to_eh_region_ranges (void)
   int min_labelno = 0, max_labelno = 0;
   int saved_call_site_base = call_site_base;
 
-  if (USING_SJLJ_EXCEPTIONS || cfun->eh->region_tree == NULL)
-    return 0;
-
-  VARRAY_UCHAR_INIT (crtl->eh.action_record_data, 64, "action_record_data");
+  crtl->eh.action_record_data = VEC_alloc (uchar, gc, 64);
 
   ar_hash = htab_create (31, action_record_hash, action_record_eq, free);
 
   for (iter = get_insns (); iter ; iter = NEXT_INSN (iter))
     if (INSN_P (iter))
       {
-       struct eh_region_d *region;
+       eh_landing_pad lp;
+       eh_region region;
+       bool nothrow;
        int this_action;
        rtx this_landing_pad;
 
@@ -3873,23 +2406,13 @@ convert_to_eh_region_ranges (void)
            && GET_CODE (PATTERN (insn)) == SEQUENCE)
          insn = XVECEXP (PATTERN (insn), 0, 0);
 
-       note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
-       if (!note)
-         {
-           if (! (CALL_P (insn)
-                  || (flag_non_call_exceptions
-                      && may_trap_p (PATTERN (insn)))))
-             continue;
-           this_action = -1;
-           region = NULL;
-         }
+       nothrow = get_eh_region_and_lp_from_rtx (insn, &region, &lp);
+       if (nothrow)
+         continue;
+       if (region)
+         this_action = collect_one_action_chain (ar_hash, region);
        else
-         {
-           if (INTVAL (XEXP (note, 0)) <= 0)
-             continue;
-           region = VEC_index (eh_region, cfun->eh->region_array, INTVAL (XEXP (note, 0)));
-           this_action = collect_one_action_chain (ar_hash, region);
-         }
+         this_action = -1;
 
        /* Existence of catch handlers, or must-not-throw regions
           implies that an lsda is needed (even if empty).  */
@@ -3904,15 +2427,8 @@ convert_to_eh_region_ranges (void)
            last_action = -1;
          }
 
-       /* Cleanups and handlers may share action chains but not
-          landing pads.  Collect the landing pad for this region.  */
        if (this_action >= 0)
-         {
-           struct eh_region_d *o;
-           for (o = region; ! o->landing_pad ; o = o->outer)
-             continue;
-           this_landing_pad = o->landing_pad;
-         }
+         this_landing_pad = lp->landing_pad;
        else
          this_landing_pad = NULL_RTX;
 
@@ -4116,12 +2632,19 @@ convert_to_eh_region_ranges (void)
   return 0;
 }
 
+static bool
+gate_convert_to_eh_region_ranges (void)
+{
+  /* Nothing to do for SJLJ exceptions or if no regions created.  */
+  return !(USING_SJLJ_EXCEPTIONS || cfun->eh->region_tree == NULL);
+}
+
 struct rtl_opt_pass pass_convert_to_eh_region_ranges =
 {
  {
   RTL_PASS,
   "eh_ranges",                          /* name */
-  NULL,                                 /* gate */
+  gate_convert_to_eh_region_ranges,    /* gate */
   convert_to_eh_region_ranges,          /* execute */
   NULL,                                 /* sub */
   NULL,                                 /* next */
@@ -4134,10 +2657,9 @@ struct rtl_opt_pass pass_convert_to_eh_region_ranges =
   TODO_dump_func,                      /* todo_flags_finish */
  }
 };
-
 \f
 static void
-push_uleb128 (varray_type *data_area, unsigned int value)
+push_uleb128 (VEC (uchar, gc) **data_area, unsigned int value)
 {
   do
     {
@@ -4145,13 +2667,13 @@ push_uleb128 (varray_type *data_area, unsigned int value)
       value >>= 7;
       if (value)
        byte |= 0x80;
-      VARRAY_PUSH_UCHAR (*data_area, byte);
+      VEC_safe_push (uchar, gc, *data_area, byte);
     }
   while (value);
 }
 
 static void
-push_sleb128 (varray_type *data_area, int value)
+push_sleb128 (VEC (uchar, gc) **data_area, int value)
 {
   unsigned char byte;
   int more;
@@ -4164,7 +2686,7 @@ push_sleb128 (varray_type *data_area, int value)
                || (value == -1 && (byte & 0x40) != 0));
       if (more)
        byte |= 0x80;
-      VARRAY_PUSH_UCHAR (*data_area, byte);
+      VEC_safe_push (uchar, gc, *data_area, byte);
     }
   while (more);
 }
@@ -4394,7 +2916,7 @@ static void
 output_one_function_exception_table (const char * ARG_UNUSED (fnname),
                                     int section, rtx ARG_UNUSED (personality))
 {
-  int tt_format, cs_format, lp_format, i, n;
+  int tt_format, cs_format, lp_format, i;
 #ifdef HAVE_AS_LEB128
   char ttype_label[32];
   char cs_after_size_label[32];
@@ -4419,8 +2941,10 @@ output_one_function_exception_table (const char * ARG_UNUSED (fnname),
   /* If the target wants a label to begin the table, emit it here.  */
   targetm.asm_out.except_table_label (asm_out_file);
 
-  have_tt_data = (VEC_length (tree, crtl->eh.ttype_data) > 0
-                 || VARRAY_ACTIVE_SIZE (crtl->eh.ehspec_data) > 0);
+  have_tt_data = (VEC_length (tree, cfun->eh->ttype_data)
+                 || (targetm.arm_eabi_unwinder
+                     ? VEC_length (tree, cfun->eh->ehspec_data.arm_eabi)
+                     : VEC_length (uchar, cfun->eh->ehspec_data.other)));
 
   /* Indicate the format of the @TType entries.  */
   if (! have_tt_data)
@@ -4483,8 +3007,8 @@ output_one_function_exception_table (const char * ARG_UNUSED (fnname),
       before_disp = 1 + 1;
       after_disp = (1 + size_of_uleb128 (call_site_len)
                    + call_site_len
-                   + VARRAY_ACTIVE_SIZE (crtl->eh.action_record_data)
-                   + (VEC_length (tree, crtl->eh.ttype_data)
+                   + VEC_length (uchar, crtl->eh.action_record_data)
+                   + (VEC_length (tree, cfun->eh->ttype_data)
                       * tt_format_size));
 
       disp = after_disp;
@@ -4540,18 +3064,19 @@ output_one_function_exception_table (const char * ARG_UNUSED (fnname),
 #endif
 
   /* ??? Decode and interpret the data for flag_debug_asm.  */
-  n = VARRAY_ACTIVE_SIZE (crtl->eh.action_record_data);
-  for (i = 0; i < n; ++i)
-    dw2_asm_output_data (1, VARRAY_UCHAR (crtl->eh.action_record_data, i),
-                        (i ? NULL : "Action record table"));
+  {
+    uchar uc;
+    for (i = 0; VEC_iterate (uchar, crtl->eh.action_record_data, i, uc); ++i)
+      dw2_asm_output_data (1, uc, i ? NULL : "Action record table");
+  }
 
   if (have_tt_data)
     assemble_align (tt_format_size * BITS_PER_UNIT);
 
-  i = VEC_length (tree, crtl->eh.ttype_data);
+  i = VEC_length (tree, cfun->eh->ttype_data);
   while (i-- > 0)
     {
-      tree type = VEC_index (tree, crtl->eh.ttype_data, i);
+      tree type = VEC_index (tree, cfun->eh->ttype_data, i);
       output_ttype (type, tt_format, tt_format_size);
     }
 
@@ -4561,17 +3086,20 @@ output_one_function_exception_table (const char * ARG_UNUSED (fnname),
 #endif
 
   /* ??? Decode and interpret the data for flag_debug_asm.  */
-  n = VARRAY_ACTIVE_SIZE (crtl->eh.ehspec_data);
-  for (i = 0; i < n; ++i)
+  if (targetm.arm_eabi_unwinder)
     {
-      if (targetm.arm_eabi_unwinder)
-       {
-         tree type = VARRAY_TREE (crtl->eh.ehspec_data, i);
-         output_ttype (type, tt_format, tt_format_size);
-       }
-      else
-       dw2_asm_output_data (1, VARRAY_UCHAR (crtl->eh.ehspec_data, i),
-                            (i ? NULL : "Exception specification table"));
+      tree type;
+      for (i = 0;
+          VEC_iterate (tree, cfun->eh->ehspec_data.arm_eabi, i, type); ++i)
+       output_ttype (type, tt_format, tt_format_size);
+    }
+  else
+    {
+      uchar uc;
+      for (i = 0;
+          VEC_iterate (uchar, cfun->eh->ehspec_data.other, i, uc); ++i)
+       dw2_asm_output_data (1, uc,
+                            i ? NULL : "Exception specification table");
     }
 }
 
@@ -4605,82 +3133,50 @@ get_eh_throw_stmt_table (struct function *fun)
 {
   return fun->eh->throw_stmt_table;
 }
-
-/* Return true if the function deeds a EH personality function.  */
+\f
+/* Determine if the function needs an EH personality function.  */
 
 enum eh_personality_kind
 function_needs_eh_personality (struct function *fn)
 {
-  struct eh_region_d *i;
-  int depth = 0;
   enum eh_personality_kind kind = eh_personality_none;
+  eh_region i;
 
-  i = fn->eh->region_tree;
-  if (!i)
-    return eh_personality_none;
-
-  while (1)
+  FOR_ALL_EH_REGION_FN (i, fn)
     {
       switch (i->type)
        {
-       case ERT_TRY:
-       case ERT_THROW:
-         /* Do not need a EH personality function.  */
-         break;
-
-       case ERT_MUST_NOT_THROW:
-         /* Always needs a EH personality function.  */
-         return eh_personality_lang;
-
        case ERT_CLEANUP:
          /* Can do with any personality including the generic C one.  */
          kind = eh_personality_any;
          break;
 
-       case ERT_CATCH:
+       case ERT_TRY:
        case ERT_ALLOWED_EXCEPTIONS:
          /* Always needs a EH personality function.  The generic C
             personality doesn't handle these even for empty type lists.  */
          return eh_personality_lang;
 
-       case ERT_UNKNOWN:
+       case ERT_MUST_NOT_THROW:
+         /* Always needs a EH personality function.  The language may specify
+            what abort routine that must be used, e.g. std::terminate.  */
          return eh_personality_lang;
        }
-      /* If there are sub-regions, process them.  */
-      if (i->inner)
-       i = i->inner, depth++;
-      /* If there are peers, process them.  */
-      else if (i->next_peer)
-       i = i->next_peer;
-      /* Otherwise, step back up the tree to the next peer.  */
-      else
-       {
-         do
-           {
-             i = i->outer;
-             depth--;
-             if (i == NULL)
-               return kind;
-           }
-         while (i->next_peer == NULL);
-         i = i->next_peer;
-       }
     }
 
   return kind;
 }
-
+\f
 /* Dump EH information to OUT.  */
 
 void
 dump_eh_tree (FILE * out, struct function *fun)
 {
-  struct eh_region_d *i;
+  eh_region i;
   int depth = 0;
-  static const char *const type_name[] = { "unknown", "cleanup", "try", "catch",
-                                          "allowed_exceptions", "must_not_throw",
-                                          "throw"
-                                        };
+  static const char *const type_name[] = {
+    "cleanup", "try", "allowed_exceptions", "must_not_throw"
+  };
 
   i = fun->eh->region_tree;
   if (!i)
@@ -4690,91 +3186,82 @@ dump_eh_tree (FILE * out, struct function *fun)
   while (1)
     {
       fprintf (out, "  %*s %i %s", depth * 2, "",
-              i->region_number, type_name[(int) i->type]);
-      if (i->tree_label)
-       {
-         fprintf (out, " tree_label:");
-         print_generic_expr (out, i->tree_label, 0);
-       }
-      if (i->label)
-       fprintf (out, " label:%i", INSN_UID (i->label));
-      if (i->landing_pad)
-       {
-          fprintf (out, " landing_pad:%i", INSN_UID (i->landing_pad));
-         if (NOTE_P (i->landing_pad))
-           fprintf (out, " (deleted)");
-        }
-      if (i->post_landing_pad)
-       {
-          fprintf (out, " post_landing_pad:%i", INSN_UID (i->post_landing_pad));
-         if (NOTE_P (i->post_landing_pad))
-           fprintf (out, " (deleted)");
-       }
-      if (i->resume)
+              i->index, type_name[(int) i->type]);
+
+      if (i->landing_pads)
        {
-         rtx resume_list = i->resume;
-          fprintf (out, " resume:");
-         while (GET_CODE (resume_list) == INSN_LIST)
+         eh_landing_pad lp;
+
+         fprintf (out, " land:");
+         if (current_ir_type () == IR_GIMPLE)
+           {
+             for (lp = i->landing_pads; lp ; lp = lp->next_lp)
+               {
+                 fprintf (out, "{%i,", lp->index);
+                 print_generic_expr (out, lp->post_landing_pad, 0);
+                 fputc ('}', out);
+                 if (lp->next_lp)
+                   fputc (',', out);
+               }
+           }
+         else
            {
-             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);
+             for (lp = i->landing_pads; lp ; lp = lp->next_lp);
+               {
+                 fprintf (out, "{%i,", lp->index);
+                 if (lp->landing_pad)
+                   fprintf (out, "%i%s,", INSN_UID (lp->landing_pad),
+                            NOTE_P (lp->landing_pad) ? "(del)" : "");
+                 else
+                   fprintf (out, "(nil),");
+                 if (lp->post_landing_pad)
+                   {
+                     rtx lab = label_rtx (lp->post_landing_pad);
+                     fprintf (out, "%i%s}", INSN_UID (lab),
+                              NOTE_P (lab) ? "(del)" : "");
+                   }
+                 else
+                   fprintf (out, "(nil)}");
+                 if (lp->next_lp)
+                   fputc (',', out);
+               }
            }
-          fprintf (out, " resume:%i", INSN_UID (i->resume));
-         if (NOTE_P (i->resume))
-           fprintf (out, " (deleted)");
        }
-      if (i->may_contain_throw)
-        fprintf (out, " may_contain_throw");
+
       switch (i->type)
        {
        case ERT_CLEANUP:
+       case ERT_MUST_NOT_THROW:
          break;
 
        case ERT_TRY:
          {
-           struct eh_region_d *c;
-           fprintf (out, " catch regions:");
-           for (c = i->u.eh_try.eh_catch; c; c = c->u.eh_catch.next_catch)
-             fprintf (out, " %i", c->region_number);
+           eh_catch c;
+           fprintf (out, " catch:");
+           for (c = i->u.eh_try.first_catch; c; c = c->next_catch)
+             {
+               fputc ('{', out);
+               if (c->label)
+                 {
+                   fprintf (out, "lab:");
+                   print_generic_expr (out, c->label, 0);
+                   fputc (';', out);
+                 }
+               print_generic_expr (out, c->type_list, 0);
+               fputc ('}', out);
+               if (c->next_catch)
+                 fputc (',', out);
+             }
          }
          break;
 
-       case ERT_CATCH:
-         if (i->u.eh_catch.prev_catch)
-           fprintf (out, " prev: %i",
-                    i->u.eh_catch.prev_catch->region_number);
-         if (i->u.eh_catch.next_catch)
-           fprintf (out, " next %i",
-                    i->u.eh_catch.next_catch->region_number);
-         fprintf (out, " type:");
-         print_generic_expr (out, i->u.eh_catch.type_list, 0);
-         break;
-
        case ERT_ALLOWED_EXCEPTIONS:
          fprintf (out, " filter :%i types:", i->u.allowed.filter);
          print_generic_expr (out, i->u.allowed.type_list, 0);
          break;
-
-       case ERT_THROW:
-         fprintf (out, " type:");
-         print_generic_expr (out, i->u.eh_throw.type, 0);
-         break;
-
-       case ERT_MUST_NOT_THROW:
-         break;
-
-       case ERT_UNKNOWN:
-         break;
-       }
-      if (i->aka)
-       {
-         fprintf (out, " also known as:");
-         dump_bitmap (out, i->aka);
        }
-      else
-       fprintf (out, "\n");
+      fputc ('\n', out);
+
       /* If there are sub-regions, process them.  */
       if (i->inner)
        i = i->inner, depth++;
@@ -4805,217 +3292,123 @@ debug_eh_tree (struct function *fn)
   dump_eh_tree (stderr, fn);
 }
 
-
-/* Verify EH region invariants.  */
-
-static bool
-verify_eh_region (struct eh_region_d *region)
-{
-  bool found = false;
-  if (!region)
-    return false;
-  switch (region->type)
-    {
-    case ERT_TRY:
-      {
-       struct eh_region_d *c, *prev = NULL;
-       if (region->u.eh_try.eh_catch->u.eh_catch.prev_catch)
-         {
-           error ("Try region %i has wrong rh_catch pointer to %i",
-                  region->region_number,
-                  region->u.eh_try.eh_catch->region_number);
-           found = true;
-         }
-       for (c = region->u.eh_try.eh_catch; c; c = c->u.eh_catch.next_catch)
-         {
-           if (c->outer != region->outer)
-             {
-               error
-                 ("Catch region %i has different outer region than try region %i",
-                  c->region_number, region->region_number);
-               found = true;
-             }
-           if (c->u.eh_catch.prev_catch != prev)
-             {
-               error ("Catch region %i has corrupted catchlist",
-                      c->region_number);
-               found = true;
-             }
-           prev = c;
-         }
-       if (prev != region->u.eh_try.last_catch)
-         {
-           error
-             ("Try region %i has wrong last_catch pointer to %i instead of %i",
-              region->region_number,
-              region->u.eh_try.last_catch->region_number,
-              prev->region_number);
-           found = true;
-         }
-      }
-      break;
-    case ERT_CATCH:
-      if (!region->u.eh_catch.prev_catch
-          && (!region->next_peer || region->next_peer->type != ERT_TRY))
-       {
-         error ("Catch region %i should be followed by try", region->region_number);
-         found = true;
-       }
-      break;
-    case ERT_CLEANUP:
-    case ERT_ALLOWED_EXCEPTIONS:
-    case ERT_MUST_NOT_THROW:
-    case ERT_THROW:
-      break;
-    case ERT_UNKNOWN:
-      gcc_unreachable ();
-    }
-  for (region = region->inner; region; region = region->next_peer)
-    found |= verify_eh_region (region);
-  return found;
-}
-
 /* Verify invariants on EH datastructures.  */
 
 void
 verify_eh_tree (struct function *fun)
 {
-  struct eh_region_d *i, *outer = NULL;
+  eh_region r, outer;
+  int nvisited_lp, nvisited_r;
+  int count_lp, count_r, depth, i;
+  eh_landing_pad lp;
   bool err = false;
-  int nvisited = 0;
-  int count = 0;
-  int j;
-  int depth = 0;
 
   if (!fun->eh->region_tree)
     return;
-  for (j = fun->eh->last_region_number; j > 0; --j)
-    if ((i = VEC_index (eh_region, fun->eh->region_array, j)))
+
+  count_r = 0;
+  for (i = 1; VEC_iterate (eh_region, fun->eh->region_array, i, r); ++i)
+    if (r)
       {
-       if (i->region_number == j)
-         count++;
-       if (i->region_number != j && (!i->aka || !bitmap_bit_p (i->aka, j)))
+       if (r->index == i)
+         count_r++;
+       else
          {
-           error ("region_array is corrupted for region %i",
-                  i->region_number);
+           error ("region_array is corrupted for region %i", r->index);
            err = true;
          }
       }
-  i = fun->eh->region_tree;
 
+  count_lp = 0;
+  for (i = 1; VEC_iterate (eh_landing_pad, fun->eh->lp_array, i, lp); ++i)
+    if (lp)
+      {
+       if (lp->index == i)
+         count_lp++;
+       else
+         {
+           error ("lp_array is corrupted for lp %i", lp->index);
+           err = true;
+         }
+      }
+
+  depth = nvisited_lp = nvisited_r = 0;
+  outer = NULL;
+  r = fun->eh->region_tree;
   while (1)
     {
-      if (VEC_index (eh_region, fun->eh->region_array, i->region_number) != i)
+      if (VEC_index (eh_region, fun->eh->region_array, r->index) != r)
        {
-         error ("region_array is corrupted for region %i", i->region_number);
+         error ("region_array is corrupted for region %i", r->index);
          err = true;
        }
-      if (i->outer != outer)
+      if (r->outer != outer)
        {
-         error ("outer block of region %i is wrong", i->region_number);
+         error ("outer block of region %i is wrong", r->index);
          err = true;
        }
-      if (i->may_contain_throw && outer && !outer->may_contain_throw)
+      if (depth < 0)
        {
-         error
-           ("region %i may contain throw and is contained in region that may not",
-            i->region_number);
+         error ("negative nesting depth of region %i", r->index);
          err = true;
        }
-      if (depth < 0)
+      nvisited_r++;
+
+      for (lp = r->landing_pads; lp ; lp = lp->next_lp)
        {
-         error ("negative nesting depth of region %i", i->region_number);
-         err = true;
+         if (VEC_index (eh_landing_pad, fun->eh->lp_array, lp->index) != lp)
+           {
+             error ("lp_array is corrupted for lp %i", lp->index);
+             err = true;
+           }
+         if (lp->region != r)
+           {
+             error ("region of lp %i is wrong", lp->index);
+             err = true;
+           }
+         nvisited_lp++;
        }
-      nvisited++;
-      /* If there are sub-regions, process them.  */
-      if (i->inner)
-       outer = i, i = i->inner, depth++;
-      /* If there are peers, process them.  */
-      else if (i->next_peer)
-       i = i->next_peer;
-      /* Otherwise, step back up the tree to the next peer.  */
+
+      if (r->inner)
+       outer = r, r = r->inner, depth++;
+      else if (r->next_peer)
+       r = r->next_peer;
       else
        {
          do
            {
-             i = i->outer;
+             r = r->outer;
+             if (r == NULL)
+               goto region_done;
              depth--;
-             if (i == NULL)
-               {
-                 if (depth != -1)
-                   {
-                     error ("tree list ends on depth %i", depth + 1);
-                     err = true;
-                   }
-                 if (count != nvisited)
-                   {
-                     error ("array does not match the region tree");
-                     err = true;
-                   }
-                 if (!err)
-                   for (i = fun->eh->region_tree; i; i = i->next_peer)
-                     err |= verify_eh_region (i);
-                 
-                 if (err)
-                   {
-                     dump_eh_tree (stderr, fun);
-                     internal_error ("verify_eh_tree failed");
-                   }
-                 return;
-               }
-             outer = i->outer;
+             outer = r->outer;
            }
-         while (i->next_peer == NULL);
-         i = i->next_peer;
+         while (r->next_peer == NULL);
+         r = r->next_peer;
        }
     }
-}
-
-/* Initialize unwind_resume_libfunc.  */
+ region_done:
+  if (depth != 0)
+    {
+      error ("tree list ends on depth %i", depth);
+      err = true;
+    }
+  if (count_r != nvisited_r)
+    {
+      error ("region_array does not match region_tree");
+      err = true;
+    }
+  if (count_lp != nvisited_lp)
+    {
+      error ("lp_array does not match region_tree");
+      err = true;
+    }
 
-void
-default_init_unwind_resume_libfunc (void)
-{
-  /* The default c++ routines aren't actually c++ specific, so use those.  */
-  unwind_resume_libfunc =
-    init_one_libfunc ( USING_SJLJ_EXCEPTIONS ? "_Unwind_SjLj_Resume"
-                                            : "_Unwind_Resume");
+  if (err)
+    {
+      dump_eh_tree (stderr, fun);
+      internal_error ("verify_eh_tree failed");
+    }
 }
-
 \f
-static bool
-gate_handle_eh (void)
-{
-  return doing_eh (0);
-}
-
-/* Complete generation of exception handling code.  */
-static unsigned int
-rest_of_handle_eh (void)
-{
-  finish_eh_generation ();
-  cleanup_cfg (CLEANUP_NO_INSN_DEL);
-  return 0;
-}
-
-struct rtl_opt_pass pass_rtl_eh =
-{
- {
-  RTL_PASS,
-  "eh",                                 /* name */
-  gate_handle_eh,                       /* gate */
-  rest_of_handle_eh,                   /* execute */
-  NULL,                                 /* sub */
-  NULL,                                 /* next */
-  0,                                    /* static_pass_number */
-  TV_JUMP,                              /* tv_id */
-  0,                                    /* properties_required */
-  0,                                    /* properties_provided */
-  0,                                    /* properties_destroyed */
-  0,                                    /* todo_flags_start */
-  TODO_dump_func                        /* todo_flags_finish */
- }
-};
-
 #include "gt-except.h"
index af63e98..3e9a39c 100644 (file)
@@ -23,20 +23,96 @@ along with GCC; see the file COPYING3.  If not see
 #include "vecprim.h"
 
 struct function;
+struct eh_region_d;
+struct pointer_map_t;
 
 /* The type of an exception region.  */
 enum eh_region_type
 {
-  ERT_UNKNOWN = 0,
+  /* CLEANUP regions implement e.g. destructors run when exiting a block.
+     They can be generated from both GIMPLE_TRY_FINALLY and GIMPLE_TRY_CATCH
+     nodes.  It is expected by the runtime that cleanup regions will *not*
+     resume normal program flow, but will continue propagation of the
+     exception.  */
   ERT_CLEANUP,
+
+  /* TRY regions implement catching an exception.  The list of types associated
+     with the attached catch handlers is examined in order by the runtime and
+     control is transfered to the appropriate handler.  Note that a NULL type
+     list is a catch-all handler, and that it will catch *all* exceptions
+     including those originating from a different language.  */
   ERT_TRY,
-  ERT_CATCH,
+
+  /* ALLOWED_EXCEPTIONS regions implement exception filtering, e.g. the
+     throw(type-list) specification that can be added to C++ functions.
+     The runtime examines the thrown exception vs the type list, and if
+     the exception does not match, transfers control to the handler.  The
+     normal handler for C++ calls __cxa_call_unexpected.  */
   ERT_ALLOWED_EXCEPTIONS,
-  ERT_MUST_NOT_THROW,
-  ERT_THROW
+
+  /* MUST_NOT_THROW regions prevent all exceptions from propagating.  This
+     region type is used in C++ to surround destructors being run inside a
+     CLEANUP region.  This differs from an ALLOWED_EXCEPTIONS region with
+     an empty type list in that the runtime is prepared to terminate the
+     program directly.  We only generate code for MUST_NOT_THROW regions
+     along control paths that are already handling an exception within the
+     current function.  */
+  ERT_MUST_NOT_THROW
+};
+
+
+/* A landing pad for a given exception region.  Any transfer of control
+   from the EH runtime to the function happens at a landing pad.  */
+
+struct GTY(()) eh_landing_pad_d
+{
+  /* The linked list of all landing pads associated with the region.  */
+  struct eh_landing_pad_d *next_lp;
+
+  /* The region with which this landing pad is associated.  */
+  struct eh_region_d *region;
+
+  /* At the gimple level, the location to which control will be transfered
+     for this landing pad.  There can be both EH and normal edges into the
+     block containing the post-landing-pad label.  */
+  tree post_landing_pad;
+
+  /* At the rtl level, the location to which the runtime will transfer
+     control.  This differs from the post-landing-pad in that the target's
+     EXCEPTION_RECEIVER pattern will be expanded here, as well as other
+     bookkeeping specific to exceptions.  There must not be normal edges
+     into the block containing the landing-pad label.  */
+  rtx landing_pad;
+
+  /* The index of this landing pad within fun->eh->lp_array.  */
+  int index;
+};
+
+/* A catch handler associated with an ERT_TRY region.  */
+
+struct GTY(()) eh_catch_d
+{
+  /* The double-linked list of all catch handlers for the region.  */
+  struct eh_catch_d *next_catch;
+  struct eh_catch_d *prev_catch;
+
+  /* A TREE_LIST of runtime type objects that this catch handler
+     will catch, or NULL if all exceptions are caught.  */
+  tree type_list;
+
+  /* A TREE_LIST of INTEGER_CSTs that correspond to the type_list entries,
+     having been mapped by assign_filter_values.  These integers are to be
+     compared against the __builtin_eh_filter value.  */
+  tree filter_list;
+
+  /* The code that should be executed if this catch handler matches the
+     thrown exception.  This label is only maintained until
+     pass_lower_eh_dispatch, at which point it is cleared.  */
+  tree label;
 };
 
 /* Describes one exception region.  */
+
 struct GTY(()) eh_region_d
 {
   /* The immediately surrounding region.  */
@@ -46,124 +122,123 @@ struct GTY(()) eh_region_d
   struct eh_region_d *inner;
   struct eh_region_d *next_peer;
 
-  /* List of regions sharing label.  */
-  struct eh_region_d *next_region_sharing_label;
-
-  /* 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;
+  /* The index of this region within fun->eh->region_array.  */
+  int index;
 
   /* Each region does exactly one thing.  */
   enum eh_region_type type;
 
   /* Holds the action to perform based on the preceding type.  */
   union eh_region_u {
-    /* A list of catch blocks, a surrounding try block,
-       and the label for continuing after a catch.  */
     struct eh_region_u_try {
-      struct eh_region_d *eh_catch;
-      struct eh_region_d *last_catch;
+      /* The double-linked list of all catch handlers for this region.  */
+      struct eh_catch_d *first_catch;
+      struct eh_catch_d *last_catch;
     } GTY ((tag ("ERT_TRY"))) eh_try;
 
-    /* The list through the catch handlers, the list of type objects
-       matched, and the list of associated filters.  */
-    struct eh_region_u_catch {
-      struct eh_region_d *next_catch;
-      struct eh_region_d *prev_catch;
-      tree type_list;
-      tree filter_list;
-    } GTY ((tag ("ERT_CATCH"))) eh_catch;
-
-    /* A tree_list of allowed types.  */
     struct eh_region_u_allowed {
+      /* A TREE_LIST of runtime type objects allowed to pass.  */
       tree type_list;
+      /* The code that should be executed if the thrown exception does
+        not match the type list.  This label is only maintained until
+        pass_lower_eh_dispatch, at which point it is cleared.  */
+      tree label;
+      /* The integer that will be passed by the runtime to signal that
+        we should execute the code at LABEL.  This integer is assigned
+        by assign_filter_values and is to be compared against the
+        __builtin_eh_filter value.  */
       int filter;
     } GTY ((tag ("ERT_ALLOWED_EXCEPTIONS"))) allowed;
 
-    /* The type given by a call to "throw foo();", or discovered
-       for a throw.  */
-    struct eh_region_u_throw {
-      tree type;
-    } GTY ((tag ("ERT_THROW"))) eh_throw;
+    struct eh_region_u_must_not_throw {
+      /* A function decl to be invoked if this region is actually reachable
+        from within the function, rather than implementable from the runtime.
+        The normal way for this to happen is for there to be a CLEANUP region
+        contained within this MUST_NOT_THROW region.  Note that if the
+        runtime handles the MUST_NOT_THROW region, we have no control over
+        what termination function is called; it will be decided by the 
+        personality function in effect for this CIE.  */
+      tree failure_decl;
+      /* The location assigned to the call of FAILURE_DECL, if expanded.  */
+      location_t failure_loc;
+    } GTY ((tag ("ERT_MUST_NOT_THROW"))) must_not_throw;
   } GTY ((desc ("%0.type"))) u;
 
-  /* Entry point for this region's handler before landing pads are built.  */
-  rtx label;
-  tree tree_label;
-
-  /* Entry point for this region's handler from the runtime eh library.  */
-  rtx landing_pad;
-
-  /* Entry point for this region's handler from an inner region.  */
-  rtx post_landing_pad;
+  /* The list of landing pads associated with this region.  */
+  struct eh_landing_pad_d *landing_pads;
 
-  /* The RESX insn for handing off control to the next outermost handler,
-     if appropriate.  */
-  rtx resume;
-
-  /* True if something in this region may throw.  */
-  unsigned may_contain_throw : 1;
+  /* EXC_PTR and FILTER values copied from the runtime for this region.
+     Each region gets its own psuedos so that if there are nested exceptions
+     we do not overwrite the values of the first exception.  */
+  rtx exc_ptr_reg, filter_reg;
 };
 
+typedef struct eh_landing_pad_d *eh_landing_pad;
+typedef struct eh_catch_d *eh_catch;
 typedef struct eh_region_d *eh_region;
+
 DEF_VEC_P(eh_region);
 DEF_VEC_ALLOC_P(eh_region, gc);
 DEF_VEC_ALLOC_P(eh_region, heap);
 
-/* Per-function EH data.  Used to save exception status for each
-   function.  */
+DEF_VEC_P(eh_landing_pad);
+DEF_VEC_ALLOC_P(eh_landing_pad, gc);
+
+
+/* The exception status for each function.  */
+
 struct GTY(()) eh_status
 {
   /* The tree of all regions for this function.  */
-  struct eh_region_d *region_tree;
+  eh_region region_tree;
 
   /* The same information as an indexable array.  */
   VEC(eh_region,gc) *region_array;
-  int last_region_number;
 
+  /* The landing pads as an indexable array.  */
+  VEC(eh_landing_pad,gc) *lp_array;
+
+  /* At the gimple level, a mapping from gimple statement to landing pad
+     or must-not-throw region.  See record_stmt_eh_region.  */
   htab_t GTY((param_is (struct throw_stmt_node))) throw_stmt_table;
+
+  /* All of the runtime type data used by the function.  These objects
+     are emitted to the lang-specific-data-area for the function.  */
+  VEC(tree,gc) *ttype_data;
+
+  /* The table of all action chains.  These encode the eh_region tree in
+     a compact form for use by the runtime, and is also emitted to the
+     lang-specific-data-area.  Note that the ARM EABI uses a different
+     format for the encoding than all other ports.  */
+  union eh_status_u {
+    VEC(tree,gc) * GTY((tag ("1"))) arm_eabi;
+    VEC(uchar,gc) * GTY((tag ("0"))) other;
+  } GTY ((desc ("targetm.arm_eabi_unwinder"))) ehspec_data;
 };
 
 
 /* Test: is exception handling turned on?  */
 extern int doing_eh (int);
 
-/* Note that the current EH region (if any) may contain a throw, or a
-   call to a function which itself may contain a throw.  */
-extern void note_eh_region_may_contain_throw (struct eh_region_d *);
-
 /* 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 (void (*) (rtx));
 
-/* Invokes CALLBACK for every exception region in the current function.  */
-extern void for_each_eh_region (void (*) (struct eh_region_d *));
-
-/* Determine if the given INSN can throw an exception.  */
-extern bool can_throw_internal_1 (int, bool, bool);
-extern bool can_throw_internal (const_rtx);
-extern bool can_throw_external_1 (int, bool, bool);
-extern bool can_throw_external (const_rtx);
-
 /* Set TREE_NOTHROW and cfun->all_throwers_are_sibcalls.  */
 extern unsigned int set_nothrow_function_flags (void);
 
 extern void init_eh (void);
 extern void init_eh_for_function (void);
 
-extern rtx reachable_handlers (rtx);
-extern void remove_eh_region (int);
-extern void remove_eh_region_and_replace_by_outer_of (int, int);
+extern void remove_eh_landing_pad (eh_landing_pad);
+extern void remove_eh_handler (eh_region);
 
-extern void convert_from_eh_region_ranges (void);
-extern unsigned int convert_to_eh_region_ranges (void);
-extern void find_exception_handler_labels (void);
 extern bool current_function_has_exception_handlers (void);
 extern void output_function_exception_table (const char *);
 
+extern rtx expand_builtin_eh_pointer (tree);
+extern rtx expand_builtin_eh_filter (tree);
+extern rtx expand_builtin_eh_copy_values (tree);
 extern void expand_builtin_unwind_init (void);
 extern rtx expand_builtin_eh_return_data_regno (tree);
 extern rtx expand_builtin_extract_return_addr (tree);
@@ -173,46 +248,50 @@ extern rtx expand_builtin_dwarf_sp_column (void);
 extern void expand_builtin_eh_return (tree, tree);
 extern void expand_eh_return (void);
 extern rtx expand_builtin_extend_pointer (tree);
-extern rtx get_exception_pointer (void);
-extern rtx get_exception_filter (void);
+
 typedef tree (*duplicate_eh_regions_map) (tree, void *);
-extern int duplicate_eh_regions (struct function *, duplicate_eh_regions_map,
-                                void *, int, int);
+extern struct pointer_map_t *duplicate_eh_regions
+  (struct function *, eh_region, int, duplicate_eh_regions_map, void *);
 
 extern void sjlj_emit_function_exit_after (rtx);
-extern void default_init_unwind_resume_libfunc (void);
-
-extern struct eh_region_d *gen_eh_region_cleanup (struct eh_region_d *);
-extern struct eh_region_d *gen_eh_region_try (struct eh_region_d *);
-extern struct eh_region_d *gen_eh_region_catch (struct eh_region_d *, tree);
-extern struct eh_region_d *gen_eh_region_allowed (struct eh_region_d *, tree);
-extern struct eh_region_d *gen_eh_region_must_not_throw (struct eh_region_d *);
-extern int get_eh_region_number (struct eh_region_d *);
-extern bool get_eh_region_may_contain_throw (struct eh_region_d *);
-extern tree get_eh_region_no_tree_label (int);
-extern tree get_eh_region_tree_label (struct eh_region_d *);
-extern void set_eh_region_tree_label (struct eh_region_d *, tree);
-
-extern void foreach_reachable_handler (int, bool, bool,
-                                      void (*) (struct eh_region_d *, void *),
-                                      void *);
-
-extern void collect_eh_region_array (void);
-extern void expand_resx_stmt (gimple);
+
+extern eh_region gen_eh_region_cleanup (eh_region);
+extern eh_region gen_eh_region_try (eh_region);
+extern eh_region gen_eh_region_allowed (eh_region, tree);
+extern eh_region gen_eh_region_must_not_throw (eh_region);
+
+extern eh_catch gen_eh_region_catch (eh_region, tree);
+extern eh_landing_pad gen_eh_landing_pad (eh_region);
+
+extern eh_region get_eh_region_from_number_fn (struct function *, int);
+extern eh_region get_eh_region_from_number (int);
+extern eh_landing_pad get_eh_landing_pad_from_number_fn (struct function*,int);
+extern eh_landing_pad get_eh_landing_pad_from_number (int);
+extern eh_region get_eh_region_from_lp_number_fn (struct function *, int);
+extern eh_region get_eh_region_from_lp_number (int);
+
+extern eh_region eh_region_outermost (struct function *, eh_region, eh_region);
+
+extern void make_reg_eh_region_note (rtx insn, int ecf_flags, int lp_nr);
+extern void make_reg_eh_region_note_nothrow_nononlocal (rtx);
+
 extern void verify_eh_tree (struct function *);
 extern void dump_eh_tree (FILE *, struct function *);
 void debug_eh_tree (struct function *);
-extern int eh_region_outermost (struct function *, int, int);
 extern void add_type_for_runtime (tree);
 extern tree lookup_type_for_runtime (tree);
+extern void assign_filter_values (void);
+
+extern eh_region get_eh_region_from_rtx (const_rtx);
+extern eh_landing_pad get_eh_landing_pad_from_rtx (const_rtx);
 
-/* If non-NULL, this is a function that returns an expression to be
+/* If non-NULL, this is a function that returns a function decl to be
    executed if an unhandled exception is propagated out of a cleanup
    region.  For example, in C++, an exception thrown by a destructor
    during stack unwinding is required to result in a call to
    `std::terminate', so the C++ version of this function returns a
-   CALL_EXPR for `std::terminate'.  */
-extern gimple (*lang_protect_cleanup_actions) (void);
+   FUNCTION_DECL for `std::terminate'.  */
+extern tree (*lang_protect_cleanup_actions) (void);
 
 /* Return true if type A catches type B.  */
 extern int (*lang_eh_type_covers) (tree a, tree b);
@@ -263,17 +342,11 @@ extern int (*lang_eh_type_covers) (tree a, tree b);
 
 struct GTY(()) throw_stmt_node {
   gimple stmt;
-  int region_nr;
+  int lp_nr;
 };
 
 extern struct htab *get_eh_throw_stmt_table (struct function *);
 extern void set_eh_throw_stmt_table (struct function *, struct htab *);
-extern void remove_unreachable_regions (sbitmap, sbitmap);
-extern VEC(int,heap) * label_to_region_map (void);
-extern int num_eh_regions (void);
-extern bitmap must_not_throw_labels (void);
-extern struct eh_region_d *redirect_eh_edge_to_label (struct edge_def *, tree, bool, bool, int);
-extern int get_next_region_sharing_label (int);
 
 enum eh_personality_kind {
   eh_personality_none,
@@ -283,3 +356,34 @@ enum eh_personality_kind {
 
 extern enum eh_personality_kind
 function_needs_eh_personality (struct function *);
+
+/* Pre-order iteration within the eh_region tree.  */
+
+static inline eh_region
+ehr_next (eh_region r, eh_region start)
+{
+  if (r->inner)
+    r = r->inner;
+  else if (r->next_peer && r != start)
+    r = r->next_peer;
+  else
+    {
+      do
+       {
+         r = r->outer;
+         if (r == start)
+           return NULL;
+       }
+      while (r->next_peer == NULL);
+      r = r->next_peer;
+    }
+  return r;
+}
+
+#define FOR_ALL_EH_REGION_AT(R, START) \
+  for ((R) = (START); (R) != NULL; (R) = ehr_next (R, START))
+
+#define FOR_ALL_EH_REGION_FN(R, FN) \
+  for ((R) = (FN)->eh->region_tree; (R) != NULL; (R) = ehr_next (R, NULL))
+
+#define FOR_ALL_EH_REGION(R) FOR_ALL_EH_REGION_FN (R, cfun)
index be3b5bb..5d18435 100644 (file)
@@ -7110,7 +7110,7 @@ rtx
 expand_expr_real (tree exp, rtx target, enum machine_mode tmode,
                  enum expand_modifier modifier, rtx *alt_rtl)
 {
-  int rn = -1;
+  int lp_nr = 0;
   rtx ret, last = NULL;
 
   /* Handle ERROR_MARK before anybody tries to access its type.  */
@@ -7123,10 +7123,8 @@ expand_expr_real (tree exp, rtx target, enum machine_mode tmode,
 
   if (flag_non_call_exceptions)
     {
-      rn = lookup_expr_eh_region (exp);
-
-      /* If rn < 0, then either (1) tree-ssa not used or (2) doesn't throw.  */
-      if (rn >= 0)
+      lp_nr = lookup_expr_eh_lp (exp);
+      if (lp_nr)
        last = get_last_insn ();
     }
 
@@ -7159,7 +7157,7 @@ expand_expr_real (tree exp, rtx target, enum machine_mode tmode,
   /* If using non-call exceptions, mark all insns that may trap.
      expand_call() will mark CALL_INSNs before we get to this code,
      but it doesn't handle libcalls, and these may trap.  */
-  if (rn >= 0)
+  if (lp_nr)
     {
       rtx insn;
       for (insn = next_real_insn (last); insn;
@@ -7170,8 +7168,8 @@ expand_expr_real (tree exp, rtx target, enum machine_mode tmode,
                 may_trap_p instruction may throw.  */
              && GET_CODE (PATTERN (insn)) != CLOBBER
              && GET_CODE (PATTERN (insn)) != USE
-             && (CALL_P (insn) || may_trap_p (PATTERN (insn))))
-           add_reg_note (insn, REG_EH_REGION, GEN_INT (rn));
+             && insn_could_throw_p (insn))
+           make_reg_eh_region_note (insn, 0, lp_nr);
        }
     }
 
@@ -7239,6 +7237,7 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
 
   switch (code)
     {
+    case NON_LVALUE_EXPR:
     case PAREN_EXPR:
     CASE_CONVERT:
       if (treeop0 == error_mark_node)
@@ -9490,7 +9489,6 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
     case GOTO_EXPR:
     case SWITCH_EXPR:
     case ASM_EXPR:
-    case RESX_EXPR:
       /* Expanded in cfgexpand.c.  */
       gcc_unreachable ();
 
@@ -9519,12 +9517,6 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       /* Lowered by gimplify.c.  */
       gcc_unreachable ();
 
-    case EXC_PTR_EXPR:
-      return get_exception_pointer ();
-
-    case FILTER_EXPR:
-      return get_exception_filter ();
-
     case FDESC_EXPR:
       /* Function descriptors are not valid except for as
         initialization constants, and should not be expanded.  */
index 342e376..1ce0013 100644 (file)
@@ -15224,9 +15224,7 @@ tree_expr_nonnegative_warnv_p (tree t, bool *strict_overflow_p)
     case ASSERT_EXPR:
     case ADDR_EXPR:
     case WITH_SIZE_EXPR:
-    case EXC_PTR_EXPR:
     case SSA_NAME:
-    case FILTER_EXPR:
       return tree_single_nonnegative_warnv_p (t, strict_overflow_p);
 
     default:
@@ -15518,9 +15516,7 @@ tree_expr_nonzero_warnv_p (tree t, bool *strict_overflow_p)
     case ASSERT_EXPR:
     case ADDR_EXPR:
     case WITH_SIZE_EXPR:
-    case EXC_PTR_EXPR:
     case SSA_NAME:
-    case FILTER_EXPR:
       return tree_single_nonzero_warnv_p (t, strict_overflow_p);
 
     case COMPOUND_EXPR:
index 7cf6e86..b8586c2 100644 (file)
@@ -1,3 +1,10 @@
+2009-09-14  Richard Henderson  <rth@redhat.com>
+
+       * f95-lang.c (gfc_init_builtin_functions): Update call to
+       build_common_builtin_nodes.
+       (gfc_maybe_initialize_eh): Don't call
+       default_init_unwind_resume_libfunc.
+
 2009-09-13  Richard Guenther  <rguenther@suse.de>
        Rafael Avila de Espindola  <espindola@google.com>
 
index 3d94fd6..a21044c 100644 (file)
@@ -1131,7 +1131,7 @@ gfc_init_builtin_functions (void)
                      BUILT_IN_EMUTLS_REGISTER_COMMON,
                      "__emutls_register_common", false);
 
-  build_common_builtin_nodes ();
+  build_common_builtin_nodes (false);
   targetm.init_builtins ();
 }
 
@@ -1155,7 +1155,6 @@ gfc_maybe_initialize_eh (void)
     return;
 
   gfc_eh_initialized_p = true;
-  default_init_unwind_resume_libfunc ();
   using_eh_for_cleanups ();
 }
 
index 446bc9d..72aad00 100644 (file)
@@ -24,7 +24,7 @@ along with GCC; see the file COPYING3.  If not see
 
 #include "tree.h"
 #include "hashtab.h"
-#include "varray.h"
+#include "vecprim.h"
 
 /* Stack of pending (incomplete) sequences saved by `start_sequence'.
    Each element describes one pending sequence.
@@ -144,11 +144,6 @@ DEF_VEC_ALLOC_P(call_site_record, gc);
 
 /* RTL representation of exception handling.  */
 struct GTY(()) rtl_eh {
-  rtx filter;
-  rtx exc_ptr;
-
-  int built_landing_pads;
-
   rtx ehr_stackadj;
   rtx ehr_handler;
   rtx ehr_label;
@@ -156,9 +151,7 @@ struct GTY(()) rtl_eh {
   rtx sjlj_fc;
   rtx sjlj_exit_after;
 
-  VEC(tree,gc) *ttype_data;
-  varray_type ehspec_data;
-  varray_type action_record_data;
+  VEC(uchar,gc) *action_record_data;
 
   VEC(call_site_record,gc) *call_site_record[2];
 };
index dc4aa8b..803ab3e 100644 (file)
@@ -1353,9 +1353,11 @@ hash_scan_set (rtx pat, rtx insn, struct hash_table_d *table)
          /* Don't GCSE something if we can't do a reg/reg copy.  */
          && can_copy_p (GET_MODE (dest))
          /* GCSE commonly inserts instruction after the insn.  We can't
-            do that easily for EH_REGION notes so disable GCSE on these
-            for now.  */
-         && !find_reg_note (insn, REG_EH_REGION, NULL_RTX)
+            do that easily for EH edges so disable GCSE on these for now.  */
+         /* ??? We can now easily create new EH landing pads at the
+            gimple level, for splitting edges; there's no reason we
+            can't do the same thing at the rtl level.  */
+         && !can_throw_internal (insn)
          /* Is SET_SRC something we want to gcse?  */
          && want_to_gcse_p (src)
          /* Don't CSE a nop.  */
@@ -1415,9 +1417,8 @@ hash_scan_set (rtx pat, rtx insn, struct hash_table_d *table)
           /* Don't GCSE something if we can't do a reg/reg copy.  */
           && can_copy_p (GET_MODE (src))
           /* GCSE commonly inserts instruction after the insn.  We can't
-             do that easily for EH_REGION notes so disable GCSE on these
-             for now.  */
-          && ! find_reg_note (insn, REG_EH_REGION, NULL_RTX)
+             do that easily for EH edges so disable GCSE on these for now.  */
+          && !can_throw_internal (insn)
           /* Is SET_DEST something we want to gcse?  */
           && want_to_gcse_p (dest)
           /* Don't CSE a nop.  */
index 1a2f38b..69fa68d 100644 (file)
@@ -1567,7 +1567,8 @@ open_base_files (void)
       "hard-reg-set.h", "basic-block.h", "cselib.h", "insn-addr.h",
       "optabs.h", "libfuncs.h", "debug.h", "ggc.h", "cgraph.h",
       "tree-flow.h", "reload.h", "cpp-id-data.h", "tree-chrec.h",
-      "cfglayout.h", "except.h", "output.h", "gimple.h", "cfgloop.h", NULL
+      "cfglayout.h", "except.h", "output.h", "gimple.h", "cfgloop.h",
+      "target.h", NULL
     };
     const char *const *ifp;
     outf_p gtype_desc_c;
index 876225b..66927d6 100644 (file)
@@ -363,7 +363,6 @@ gsi_split_seq_before (gimple_stmt_iterator *i)
 void
 gsi_replace (gimple_stmt_iterator *gsi, gimple stmt, bool update_eh_info)
 {
-  int eh_region;
   gimple orig_stmt = gsi_stmt (*gsi);
 
   if (stmt == orig_stmt)
@@ -375,14 +374,7 @@ gsi_replace (gimple_stmt_iterator *gsi, gimple stmt, bool update_eh_info)
   /* Preserve EH region information from the original statement, if
      requested by the caller.  */
   if (update_eh_info)
-    {
-      eh_region = lookup_stmt_eh_region (orig_stmt);
-      if (eh_region >= 0)
-       {
-         remove_stmt_from_eh_region (orig_stmt);
-         add_stmt_to_eh_region (stmt, eh_region);
-       }
-    }
+    maybe_clean_or_replace_eh_stmt (orig_stmt, stmt);
 
   gimple_duplicate_stmt_histograms (cfun, stmt, cfun, orig_stmt);
   gimple_remove_stmt_histograms (cfun, orig_stmt);
@@ -485,7 +477,7 @@ gsi_remove (gimple_stmt_iterator *i, bool remove_permanently)
 
   if (remove_permanently)
     {
-      remove_stmt_from_eh_region (stmt);
+      remove_stmt_from_eh_lp (stmt);
       gimple_remove_stmt_histograms (cfun, stmt);
     }
 
index eba8672..b58fd7b 100644 (file)
@@ -360,6 +360,7 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data)
     case GIMPLE_PREDICT:
     case GIMPLE_LABEL:
     case GIMPLE_SWITCH:
+    case GIMPLE_EH_MUST_NOT_THROW:
     case GIMPLE_OMP_FOR:
     case GIMPLE_OMP_SECTIONS:
     case GIMPLE_OMP_SECTIONS_SWITCH:
@@ -497,8 +498,8 @@ try_catch_may_fallthru (const_tree stmt)
     default:
       /* This case represents statements to be executed when an
         exception occurs.  Those statements are implicitly followed
-        by a RESX_EXPR to resume execution after the exception.  So
-        in this case the TRY_CATCH never falls through.  */
+        by a RESX statement to resume execution after the exception.
+        So in this case the TRY_CATCH never falls through.  */
       return false;
     }
 }
@@ -571,7 +572,6 @@ block_may_fallthru (const_tree block)
     {
     case GOTO_EXPR:
     case RETURN_EXPR:
-    case RESX_EXPR:
       /* Easy cases.  If the last statement of the block implies 
         control transfer, then we can't fall through.  */
       return false;
index 5018020..8903c66 100644 (file)
@@ -626,6 +626,8 @@ dump_gimple_label (pretty_printer *buffer, gimple gs, int spc, int flags)
     }
   if (DECL_NONLOCAL (label))
     pp_string (buffer, " [non-local]");
+  if ((flags & TDF_EH) && EH_LANDING_PAD_NR (label))
+    pp_printf (buffer, " [LP %d]", EH_LANDING_PAD_NR (label));
 }
 
 /* Dump a GIMPLE_GOTO tuple on the pretty_printer BUFFER, SPC
@@ -766,6 +768,21 @@ dump_gimple_eh_filter (pretty_printer *buffer, gimple gs, int spc, int flags)
 }
 
 
+/* Dump a GIMPLE_EH_MUST_NOT_THROW tuple.  */
+
+static void
+dump_gimple_eh_must_not_throw (pretty_printer *buffer, gimple gs,
+                              int spc, int flags)
+{
+  if (flags & TDF_RAW)
+    dump_gimple_fmt (buffer, spc, flags, "%G <%T>", gs,
+                    gimple_eh_must_not_throw_fndecl (gs));
+  else
+    dump_gimple_fmt (buffer, spc, flags, "<<<eh_must_not_throw (%T)>>>",
+                    gimple_eh_must_not_throw_fndecl (gs));
+}
+
+
 /* Dump a GIMPLE_RESX tuple on the pretty_printer BUFFER, SPC spaces of
    indent.  FLAGS specifies details to show in the dump (see TDF_* in
    tree-pass.h).  */
@@ -775,11 +792,24 @@ dump_gimple_resx (pretty_printer *buffer, gimple gs, int spc, int flags)
 {
   if (flags & TDF_RAW)
     dump_gimple_fmt (buffer, spc, flags, "%G <%d>", gs,
-                     gimple_resx_region (gs));
+                    gimple_resx_region (gs));
   else
     dump_gimple_fmt (buffer, spc, flags, "resx %d", gimple_resx_region (gs));
 }
 
+/* Dump a GIMPLE_EH_DISPATCH tuple on the pretty_printer BUFFER.  */
+
+static void
+dump_gimple_eh_dispatch (pretty_printer *buffer, gimple gs, int spc, int flags)
+{
+  if (flags & TDF_RAW)
+    dump_gimple_fmt (buffer, spc, flags, "%G <%d>", gs,
+                    gimple_eh_dispatch_region (gs));
+  else
+    dump_gimple_fmt (buffer, spc, flags, "eh_dispatch %d",
+                    gimple_eh_dispatch_region (gs));
+}
+
 /* Dump a GIMPLE_DEBUG tuple on the pretty_printer BUFFER, SPC spaces
    of indent.  FLAGS specifies details to show in the dump (see TDF_*
    in tree-pass.h).  */
@@ -1427,9 +1457,11 @@ dump_gimple_stmt (pretty_printer *buffer, gimple gs, int spc, int flags)
 
   if (flags & TDF_EH)
     {
-      int eh_region = lookup_stmt_eh_region_fn (cfun, gs);
-      if (eh_region >= 0)
-       pp_printf (buffer, "[EH #%d] ", eh_region);
+      int lp_nr = lookup_stmt_eh_lp (gs);
+      if (lp_nr > 0)
+       pp_printf (buffer, "[LP %d] ", lp_nr);
+      else if (lp_nr < 0)
+       pp_printf (buffer, "[MNT %d] ", -lp_nr);
     }
 
   if ((flags & (TDF_VOPS|TDF_MEMSYMS))
@@ -1545,10 +1577,18 @@ dump_gimple_stmt (pretty_printer *buffer, gimple gs, int spc, int flags)
       dump_gimple_eh_filter (buffer, gs, spc, flags);
       break;
 
+    case GIMPLE_EH_MUST_NOT_THROW:
+      dump_gimple_eh_must_not_throw (buffer, gs, spc, flags);
+      break;
+
     case GIMPLE_RESX:
       dump_gimple_resx (buffer, gs, spc, flags);
       break;
 
+    case GIMPLE_EH_DISPATCH:
+      dump_gimple_eh_dispatch (buffer, gs, spc, flags);
+      break;
+
     case GIMPLE_DEBUG:
       dump_gimple_debug (buffer, gs, spc, flags);
       break;
index 3be6d84..33daafc 100644 (file)
@@ -627,6 +627,20 @@ gimple_build_eh_filter (tree types, gimple_seq failure)
   return p;
 }
 
+/* Build a GIMPLE_EH_MUST_NOT_THROW statement.  */
+
+gimple
+gimple_build_eh_must_not_throw (tree decl)
+{
+  gimple p = gimple_alloc (GIMPLE_EH_MUST_NOT_THROW, 1);
+
+  gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
+  gcc_assert (flags_from_decl_or_type (decl) & ECF_NORETURN);
+  p->gimple_eh_mnt.fndecl = decl;
+
+  return p;
+}
+
 /* Build a GIMPLE_TRY statement.
 
    EVAL is the expression to evaluate.
@@ -666,16 +680,13 @@ gimple_build_wce (gimple_seq cleanup)
 }
 
 
-/* Build a GIMPLE_RESX statement.
-
-   REGION is the region number from which this resx causes control flow to 
-   leave.  */
+/* Build a GIMPLE_RESX statement.  */
 
 gimple
 gimple_build_resx (int region)
 {
-  gimple p = gimple_alloc (GIMPLE_RESX, 0);
-  gimple_resx_set_region (p, region);
+  gimple p = gimple_build_with_ops (GIMPLE_RESX, ERROR_MARK, 0);
+  p->gimple_eh_ctrl.region = region;
   return p;
 }
 
@@ -685,14 +696,15 @@ gimple_build_resx (int region)
    NLABELS is the number of labels in the switch excluding the default.
    DEFAULT_LABEL is the default label for the switch statement.  */
 
-static inline gimple 
-gimple_build_switch_1 (unsigned nlabels, tree index, tree default_label)
+gimple 
+gimple_build_switch_nlabels (unsigned nlabels, tree index, tree default_label)
 {
   /* nlabels + 1 default label + 1 index.  */
   gimple p = gimple_build_with_ops (GIMPLE_SWITCH, ERROR_MARK,
-                                   nlabels + 1 + 1);
+                                   1 + (default_label != NULL) + nlabels);
   gimple_switch_set_index (p, index);
-  gimple_switch_set_default_label (p, default_label);
+  if (default_label)
+    gimple_switch_set_default_label (p, default_label);
   return p;
 }
 
@@ -707,15 +719,14 @@ gimple
 gimple_build_switch (unsigned nlabels, tree index, tree default_label, ...)
 {
   va_list al;
-  unsigned i;
-  gimple p;
-  
-  p = gimple_build_switch_1 (nlabels, index, default_label);
+  unsigned i, offset;
+  gimple p = gimple_build_switch_nlabels (nlabels, index, default_label);
 
   /* Store the rest of the labels.  */
   va_start (al, default_label);
-  for (i = 1; i <= nlabels; i++)
-    gimple_switch_set_label (p, i, va_arg (al, tree));
+  offset = (default_label != NULL);
+  for (i = 0; i < nlabels; i++)
+    gimple_switch_set_label (p, i + offset, va_arg (al, tree));
   va_end (al);
 
   return p;
@@ -731,18 +742,26 @@ gimple_build_switch (unsigned nlabels, tree index, tree default_label, ...)
 gimple
 gimple_build_switch_vec (tree index, tree default_label, VEC(tree, heap) *args)
 {
-  unsigned i;
-  unsigned nlabels = VEC_length (tree, args);
-  gimple p = gimple_build_switch_1 (nlabels, index, default_label);
+  unsigned i, offset, nlabels = VEC_length (tree, args);
+  gimple p = gimple_build_switch_nlabels (nlabels, index, default_label);
 
-  /*  Put labels in labels[1 - (nlabels + 1)].
-     Default label is in labels[0].  */
-  for (i = 1; i <= nlabels; i++)
-    gimple_switch_set_label (p, i, VEC_index (tree, args, i - 1));
+  /* Copy the labels from the vector to the switch statement.  */
+  offset = (default_label != NULL);
+  for (i = 0; i < nlabels; i++)
+    gimple_switch_set_label (p, i + offset, VEC_index (tree, args, i));
 
   return p;
 }
 
+/* Build a GIMPLE_EH_DISPATCH statement.  */
+
+gimple
+gimple_build_eh_dispatch (int region)
+{
+  gimple p = gimple_build_with_ops (GIMPLE_EH_DISPATCH, ERROR_MARK, 0);
+  p->gimple_eh_ctrl.region = region;
+  return p;
+}
 
 /* Build a new GIMPLE_DEBUG_BIND statement.
 
@@ -2394,9 +2413,7 @@ get_gimple_rhs_num_ops (enum tree_code code)
       || (SYM) == ASSERT_EXPR                                              \
       || (SYM) == ADDR_EXPR                                                \
       || (SYM) == WITH_SIZE_EXPR                                           \
-      || (SYM) == EXC_PTR_EXPR                                             \
       || (SYM) == SSA_NAME                                                 \
-      || (SYM) == FILTER_EXPR                                              \
       || (SYM) == POLYNOMIAL_CHREC                                         \
       || (SYM) == DOT_PROD_EXPR                                                    \
       || (SYM) == VEC_COND_EXPR                                                    \
@@ -2658,7 +2675,6 @@ is_gimple_stmt (tree t)
     case EH_FILTER_EXPR:
     case CATCH_EXPR:
     case ASM_EXPR:
-    case RESX_EXPR:
     case STATEMENT_LIST:
     case OMP_PARALLEL:
     case OMP_FOR:
@@ -2784,11 +2800,6 @@ is_gimple_val (tree t)
       && !is_gimple_reg (t))
     return false;
 
-  /* FIXME make these decls.  That can happen only when we expose the
-     entire landing-pad construct at the tree level.  */
-  if (TREE_CODE (t) == EXC_PTR_EXPR || TREE_CODE (t) == FILTER_EXPR)
-    return true;
-
   return (is_gimple_variable (t) || is_gimple_min_invariant (t));
 }
 
index 1a3f345..603d97e 100644 (file)
@@ -1,6 +1,6 @@
 /* This file contains the definitions of the GIMPLE IR tuples used in GCC.
 
-   Copyright (C) 2007, 2008 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
    Contributed by Aldy Hernandez <aldyh@redhat.com>
 
 This file is part of GCC.
@@ -145,6 +145,18 @@ DEFGSCODE(GIMPLE_CATCH, "gimple_catch", GSS_CATCH)
    sequence of statements to execute on failure.  */
 DEFGSCODE(GIMPLE_EH_FILTER, "gimple_eh_filter", GSS_EH_FILTER)
 
+/* GIMPLE_EH_MUST_NOT_THROW <DECL> represents an exception barrier.
+   DECL is a noreturn function decl taking no arguments that will
+   be invoked if an exception propagates to this point.  */
+DEFGSCODE(GIMPLE_EH_MUST_NOT_THROW, "gimple_eh_must_not_throw", GSS_EH_MNT)
+
+/* GIMPLE_RESX resumes execution after an exception.  */
+DEFGSCODE(GIMPLE_RESX, "gimple_resx", GSS_EH_CTRL)
+
+/* GIMPLE_EH_DISPATCH demultiplexes an exception edge based on
+   the FILTER argument.  */
+DEFGSCODE(GIMPLE_EH_DISPATCH, "gimple_eh_dispatch", GSS_EH_CTRL)
+
 /* GIMPLE_PHI <RESULT, ARG1, ..., ARGN> represents the PHI node
 
    RESULT = PHI <ARG1, ..., ARGN>
@@ -157,10 +169,6 @@ DEFGSCODE(GIMPLE_EH_FILTER, "gimple_eh_filter", GSS_EH_FILTER)
    tree node of class tcc_constant.  */
 DEFGSCODE(GIMPLE_PHI, "gimple_phi", GSS_PHI)
 
-/* GIMPLE_RESX <REGION> resumes execution after an exception.
-   REGION is the region number being left.  */
-DEFGSCODE(GIMPLE_RESX, "gimple_resx", GSS_RESX)
-
 /* GIMPLE_TRY <TRY_KIND, EVAL, CLEANUP>
    represents a try/catch or a try/finally statement.
 
index 8ca1f28..b539623 100644 (file)
@@ -444,9 +444,6 @@ struct GTY(()) gimple_statement_eh_filter {
   /* [ WORD 1-4 ]  */
   struct gimple_statement_base gsbase;
 
-  /* Subcode: EH_FILTER_MUST_NOT_THROW.  A boolean flag analogous to
-     the tree counterpart.  */
-
   /* [ WORD 5 ]
      Filter types.  */
   tree types;
@@ -457,6 +454,16 @@ struct GTY(()) gimple_statement_eh_filter {
 };
 
 
+/* GIMPLE_EH_MUST_NOT_THROW */
+
+struct GTY(()) gimple_statement_eh_mnt {
+  /* [ WORD 1-4 ]  */
+  struct gimple_statement_base gsbase;
+
+  /* [ WORD 5 ] Abort function decl.  */
+  tree fndecl;
+};
+
 /* GIMPLE_PHI */
 
 struct GTY(()) gimple_statement_phi {
@@ -475,9 +482,10 @@ struct GTY(()) gimple_statement_phi {
 };
 
 
-/* GIMPLE_RESX */
+/* GIMPLE_RESX, GIMPLE_EH_DISPATCH */
 
-struct GTY(()) gimple_statement_resx {
+struct GTY(()) gimple_statement_eh_ctrl
+{
   /* [ WORD 1-4 ]  */
   struct gimple_statement_base gsbase;
 
@@ -733,8 +741,9 @@ union GTY ((desc ("gimple_statement_structure (&%h)"))) gimple_statement_d {
   struct gimple_statement_bind GTY ((tag ("GSS_BIND"))) gimple_bind;
   struct gimple_statement_catch GTY ((tag ("GSS_CATCH"))) gimple_catch;
   struct gimple_statement_eh_filter GTY ((tag ("GSS_EH_FILTER"))) gimple_eh_filter;
+  struct gimple_statement_eh_mnt GTY ((tag ("GSS_EH_MNT"))) gimple_eh_mnt;
   struct gimple_statement_phi GTY ((tag ("GSS_PHI"))) gimple_phi;
-  struct gimple_statement_resx GTY ((tag ("GSS_RESX"))) gimple_resx;
+  struct gimple_statement_eh_ctrl GTY ((tag ("GSS_EH_CTRL"))) gimple_eh_ctrl;
   struct gimple_statement_try GTY ((tag ("GSS_TRY"))) gimple_try;
   struct gimple_statement_wce GTY ((tag ("GSS_WCE"))) gimple_wce;
   struct gimple_statement_asm GTY ((tag ("GSS_ASM"))) gimple_asm;
@@ -788,9 +797,12 @@ gimple gimple_build_asm_vec (const char *, VEC(tree,gc) *, VEC(tree,gc) *,
                              VEC(tree,gc) *);
 gimple gimple_build_catch (tree, gimple_seq);
 gimple gimple_build_eh_filter (tree, gimple_seq);
+gimple gimple_build_eh_must_not_throw (tree);
 gimple gimple_build_try (gimple_seq, gimple_seq, enum gimple_try_flags);
 gimple gimple_build_wce (gimple_seq);
 gimple gimple_build_resx (int);
+gimple gimple_build_eh_dispatch (int);
+gimple gimple_build_switch_nlabels (unsigned, tree, tree);
 gimple gimple_build_switch (unsigned, tree, tree, ...);
 gimple gimple_build_switch_vec (tree, tree, VEC(tree,heap) *);
 gimple gimple_build_omp_parallel (gimple_seq, tree, tree, tree);
@@ -2863,26 +2875,15 @@ gimple_eh_filter_set_failure (gimple gs, gimple_seq failure)
   gs->gimple_eh_filter.failure = failure;
 }
 
-/* Return the EH_FILTER_MUST_NOT_THROW flag.  */
+/* Get the function decl to be called by the MUST_NOT_THROW region.  */
 
-static inline bool
-
-gimple_eh_filter_must_not_throw (gimple gs)
-{
-  GIMPLE_CHECK (gs, GIMPLE_EH_FILTER);
-  return gs->gsbase.subcode != 0;
-}
-
-/* Set the EH_FILTER_MUST_NOT_THROW flag to the value MNTP.  */
-
-static inline void
-gimple_eh_filter_set_must_not_throw (gimple gs, bool mntp)
+static inline tree
+gimple_eh_must_not_throw_fndecl (gimple gs)
 {
-  GIMPLE_CHECK (gs, GIMPLE_EH_FILTER);
-  gs->gsbase.subcode = (unsigned int) mntp;
+  GIMPLE_CHECK (gs, GIMPLE_EH_MUST_NOT_THROW);
+  return gs->gimple_eh_mnt.fndecl;
 }
 
-
 /* GIMPLE_TRY accessors. */
 
 /* Return the kind of try block represented by GIMPLE_TRY GS.  This is
@@ -3092,7 +3093,7 @@ static inline int
 gimple_resx_region (const_gimple gs)
 {
   GIMPLE_CHECK (gs, GIMPLE_RESX);
-  return gs->gimple_resx.region;
+  return gs->gimple_eh_ctrl.region;
 }
 
 /* Set REGION to be the region number for GIMPLE_RESX GS.  */
@@ -3101,9 +3102,26 @@ static inline void
 gimple_resx_set_region (gimple gs, int region)
 {
   GIMPLE_CHECK (gs, GIMPLE_RESX);
-  gs->gimple_resx.region = region;
+  gs->gimple_eh_ctrl.region = region;
 }
 
+/* Return the region number for GIMPLE_EH_DISPATCH GS.  */
+
+static inline int
+gimple_eh_dispatch_region (const_gimple gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_EH_DISPATCH);
+  return gs->gimple_eh_ctrl.region;
+}
+
+/* Set REGION to be the region number for GIMPLE_EH_DISPATCH GS.  */
+
+static inline void
+gimple_eh_dispatch_set_region (gimple gs, int region)
+{
+  GIMPLE_CHECK (gs, GIMPLE_EH_DISPATCH);
+  gs->gimple_eh_ctrl.region = region;
+}
 
 /* Return the number of labels associated with the switch statement GS.  */
 
@@ -4253,6 +4271,14 @@ gimple_nop_p (const_gimple g)
 }
 
 
+/* Return true if GS is a GIMPLE_RESX.  */
+
+static inline bool
+is_gimple_resx (const_gimple gs)
+{
+  return gimple_code (gs) == GIMPLE_RESX;
+}
+
 /* Return the predictor of GIMPLE_PREDICT statement GS.  */
 
 static inline enum br_predictor
index 7f1dc4a..381e611 100644 (file)
@@ -6645,11 +6645,6 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
          ret = gimplify_decl_expr (expr_p, pre_p);
          break;
 
-       case EXC_PTR_EXPR:
-         /* FIXME make this a decl.  */
-         ret = GS_ALL_DONE;
-         break;
-
        case BIND_EXPR:
          ret = gimplify_bind_expr (expr_p, pre_p);
          break;
@@ -6841,8 +6836,6 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
            gimplify_and_add (EH_FILTER_FAILURE (*expr_p), &failure);
            ehf = gimple_build_eh_filter (EH_FILTER_TYPES (*expr_p), failure);
            gimple_set_no_warning (ehf, TREE_NO_WARNING (*expr_p));
-           gimple_eh_filter_set_must_not_throw
-             (ehf, EH_FILTER_MUST_NOT_THROW (*expr_p));
            gimplify_seq_add_stmt (pre_p, ehf);
            ret = GS_ALL_DONE;
            break;
@@ -7178,7 +7171,6 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
                  && code != GOTO_EXPR
                  && code != LABEL_EXPR
                  && code != LOOP_EXPR
-                 && code != RESX_EXPR
                  && code != SWITCH_EXPR
                  && code != TRY_FINALLY_EXPR
                  && code != OMP_CRITICAL
index 97875c9..29cb90d 100644 (file)
@@ -34,7 +34,8 @@ DEFGSSTRUCT(GSS_PHI, gimple_statement_phi, false)
 DEFGSSTRUCT(GSS_TRY, gimple_statement_try, false)
 DEFGSSTRUCT(GSS_CATCH, gimple_statement_catch, false)
 DEFGSSTRUCT(GSS_EH_FILTER, gimple_statement_eh_filter, false)
-DEFGSSTRUCT(GSS_RESX, gimple_statement_resx, false)
+DEFGSSTRUCT(GSS_EH_MNT, gimple_statement_eh_mnt, false)
+DEFGSSTRUCT(GSS_EH_CTRL, gimple_statement_eh_ctrl, false)
 DEFGSSTRUCT(GSS_WCE, gimple_statement_wce, false)
 DEFGSSTRUCT(GSS_OMP, gimple_statement_omp, false)
 DEFGSSTRUCT(GSS_OMP_CRITICAL, gimple_statement_omp_critical, false)
index 79de363..c6bbece 100644 (file)
@@ -1735,7 +1735,6 @@ estimate_function_body_sizes (struct cgraph_node *node)
   tree arg;
   int freq;
   tree funtype = TREE_TYPE (node->decl);
-  bitmap must_not_throw = must_not_throw_labels ();
 
   if (dump_file)
     {
@@ -1748,35 +1747,20 @@ estimate_function_body_sizes (struct cgraph_node *node)
       freq = compute_call_stmt_bb_frequency (node->decl, bb);
       for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi))
        {
-         int this_size = estimate_num_insns (gsi_stmt (bsi), &eni_size_weights);
-         int this_time = estimate_num_insns (gsi_stmt (bsi), &eni_time_weights);
-
-         /* MUST_NOT_THROW is usually handled by runtime calling terminate and stopping
-            stacking unwinding.  However when there is local cleanup that can resume
-            to MUST_NOT_THROW then we generate explicit handler containing
-            std::terminate () call.
-            
-            Because inlining of function can introduce new cleanup region, prior
-            inlining we keep std::terinate () calls for every MUST_NOT_THROW containing
-            function call.  Wast majority of these will be eliminated after inlining
-            and crossjumping will inify possible duplicated calls.  So ignore
-            the handlers for function body estimates.  */
-         if (gimple_code (gsi_stmt (bsi)) == GIMPLE_LABEL
-             && bitmap_bit_p (must_not_throw, 
-                              LABEL_DECL_UID (gimple_label_label (gsi_stmt (bsi)))))
-           {
-             if (dump_file)
-               fprintf (dump_file, "  MUST_NOT_THROW landing pad.  Ignoring whole BB.\n");
-           }
+         gimple stmt = gsi_stmt (bsi);
+         int this_size = estimate_num_insns (stmt, &eni_size_weights);
+         int this_time = estimate_num_insns (stmt, &eni_time_weights);
+
          if (dump_file)
            {
-             fprintf (dump_file, "  freq:%6i size:%3i time:%3i ", freq, this_size, this_time);
-             print_gimple_stmt (dump_file, gsi_stmt (bsi), 0, 0);
+             fprintf (dump_file, "  freq:%6i size:%3i time:%3i ",
+                      freq, this_size, this_time);
+             print_gimple_stmt (dump_file, stmt, 0, 0);
            }
          this_time *= freq;
          time += this_time;
          size += this_size;
-         if (likely_eliminated_by_inlining_p (gsi_stmt (bsi)))
+         if (likely_eliminated_by_inlining_p (stmt))
            {
              size_inlining_benefit += this_size;
              time_inlining_benefit += this_time;
@@ -1825,7 +1809,6 @@ estimate_function_body_sizes (struct cgraph_node *node)
     }
   inline_summary (node)->time_inlining_benefit = time_inlining_benefit;
   inline_summary (node)->size_inlining_benefit = size_inlining_benefit;
-  BITMAP_FREE (must_not_throw);
 }
 
 /* Compute parameters of functions used by inliner.  */
index 201dc59..e5ff3a7 100644 (file)
@@ -346,8 +346,8 @@ check_call (funct_state local, gimple call, bool ipa)
         {
          if (dump_file)
            {
-             fprintf (dump_file, "    can throw externally in region %i\n",
-                      lookup_stmt_eh_region (call));
+             fprintf (dump_file, "    can throw externally to lp %i\n",
+                      lookup_stmt_eh_lp (call));
              if (callee_t)
                fprintf (dump_file, "     callee:%s\n",
                         IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (callee_t)));
index 62516d0..edfaab0 100644 (file)
@@ -1128,9 +1128,6 @@ check_operand (tree t)
 static void
 check_tree (tree t)
 {
-  if ((TREE_CODE (t) == EXC_PTR_EXPR) || (TREE_CODE (t) == FILTER_EXPR))
-    return;
-
   /* We want to catch here also REALPART_EXPR and IMAGEPART_EXPR,
      but they already included in handled_component_p.  */
   while (handled_component_p (t))
index a001916..0b7ec66 100644 (file)
@@ -215,10 +215,6 @@ ipa_utils_reduced_inorder (struct cgraph_node **order,
 tree
 get_base_var (tree t)
 {
-  if (TREE_CODE (t) == EXC_PTR_EXPR
-      || TREE_CODE (t) == FILTER_EXPR)
-    return t;
-
   while (!SSA_VAR_P (t) 
         && (!CONSTANT_CLASS_P (t))
         && TREE_CODE (t) != LABEL_DECL
index 6b7d930..6c58a99 100644 (file)
@@ -1,3 +1,16 @@
+2009-09-14  Richard Henderson  <rth@redhat.com>
+
+       * builtins.c (initialize_builtins): Update call to
+       build_common_builtin_nodes.
+       * decl.c (java_init_decl_processing): Don't call
+       default_init_unwind_resume_libfunc.
+       * except.c: Include tree-iterator.h.
+       (build_exception_object_var): New.
+       (build_exception_object_ref): Use it.
+       (expand_end_java_handler): Initialize it from __builtin_eh_pointer.
+       Attach all CATCH_EXPRs to a single TRY_CATCH_EXPR.
+       * java-tree.h (DECL_FUNCTION_EXC_OBJ): New.
+
 2009-09-13  Richard Guenther  <rguenther@suse.de>
        Rafael Avila de Espindola  <espindola@google.com>
 
index 6e4815b..a05ff53 100644 (file)
@@ -584,7 +584,7 @@ initialize_builtins (void)
                  build_function_type_list (ptr_type_node, int_type_node, NULL_TREE),
                  "__builtin_return_address", BUILTIN_NOTHROW);
 
-  build_common_builtin_nodes ();
+  build_common_builtin_nodes (true);
 }
 
 /* If the call matches a builtin, return the
index c9ccc9d..c593b53 100644 (file)
@@ -1,7 +1,7 @@
 /* Process declarations and variables for the GNU compiler for the
    Java(TM) language.
    Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2007,
-   2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+   2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -1188,14 +1188,8 @@ java_init_decl_processing (void)
                            build_function_type (long_type_node, t),
                            0, NOT_BUILT_IN, NULL, NULL_TREE);
 
-  /* Initialize variables for except.c.  */
-
-  if (targetm.arm_eabi_unwinder)
-    unwind_resume_libfunc = init_one_libfunc ("__cxa_end_cleanup");
-  else
-    default_init_unwind_resume_libfunc ();
-
   initialize_builtins ();
+
   soft_fmod_node = built_in_decls[BUILT_IN_FMOD];
 
   parse_version ();
index e97ed77..4e46514 100644 (file)
@@ -1,6 +1,6 @@
 /* Handle exceptions for GNU compiler for the Java(TM) language.
    Copyright (C) 1997, 1998, 1999, 2000, 2002, 2003, 2004, 2005,
-   2007, 2008 Free Software Foundation, Inc.
+   2007, 2008, 2009 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -37,6 +37,8 @@ The Free Software Foundation is independent of Sun Microsystems, Inc.  */
 #include "except.h"
 #include "java-except.h"
 #include "toplev.h"
+#include "tree-iterator.h"
+
 
 static void expand_start_java_handler (struct eh_range *);
 static struct eh_range *find_handler_in_range (int, struct eh_range *,
@@ -457,6 +459,26 @@ java_expand_catch_classes (tree this_class)
        expand_catch_class, NULL);
 }
 
+/* Build and push the variable that will hold the exception object
+   within this function.  */
+
+static tree
+build_exception_object_var (void)
+{
+  tree decl = DECL_FUNCTION_EXC_OBJ (current_function_decl);
+  if (decl == NULL)
+    {
+      decl = build_decl (DECL_SOURCE_LOCATION (current_function_decl),
+                        VAR_DECL, get_identifier ("#exc_obj"), ptr_type_node);
+      DECL_IGNORED_P (decl) = 1;
+      DECL_ARTIFICIAL (decl) = 1;
+
+      DECL_FUNCTION_EXC_OBJ (current_function_decl) = decl;
+      pushdecl_function_level (decl);
+    }
+  return decl;
+}
+
 /* Build a reference to the jthrowable object being carried in the
    exception header.  */
 
@@ -467,7 +489,8 @@ build_exception_object_ref (tree type)
 
   /* Java only passes object via pointer and doesn't require adjusting.
      The java object is immediately before the generic exception header.  */
-  obj = build0 (EXC_PTR_EXPR, build_pointer_type (type));
+  obj = build_exception_object_var ();
+  obj = fold_convert (build_pointer_type (type), obj);
   obj = build2 (POINTER_PLUS_EXPR, TREE_TYPE (obj), obj,
                fold_build1 (NEGATE_EXPR, sizetype,
                             TYPE_SIZE_UNIT (TREE_TYPE (obj))));
@@ -482,29 +505,48 @@ void
 expand_end_java_handler (struct eh_range *range)
 {  
   tree handler = range->handlers;
-
-  for ( ; handler != NULL_TREE; handler = TREE_CHAIN (handler))
+  if (handler)
     {
-      /* For bytecode we treat exceptions a little unusually.  A
-        `finally' clause looks like an ordinary exception handler for
-        Throwable.  The reason for this is that the bytecode has
-        already expanded the finally logic, and we would have to do
-        extra (and difficult) work to get this to look like a
-        gcc-style finally clause.  */
-      tree type = TREE_PURPOSE (handler);
-      if (type == NULL)
-       type = throwable_type_node;
-      type = prepare_eh_table_type (type);
+      tree exc_obj = build_exception_object_var ();
+      tree catches = make_node (STATEMENT_LIST);
+      tree_stmt_iterator catches_i = tsi_last (catches);
+      tree *body;
 
-      {
-       tree catch_expr = build2 (CATCH_EXPR, void_type_node, type,
-                                 build1 (GOTO_EXPR, void_type_node,
-                                         TREE_VALUE (handler)));
-       tree try_catch_expr = build2 (TRY_CATCH_EXPR, void_type_node,
-                                     *get_stmts (), catch_expr);       
-       *get_stmts () = try_catch_expr;
-      }
+      for (; handler; handler = TREE_CHAIN (handler))
+       {
+         tree type, eh_type, x;
+         tree stmts = make_node (STATEMENT_LIST);
+         tree_stmt_iterator stmts_i = tsi_last (stmts);
+
+         type = TREE_PURPOSE (handler);
+         if (type == NULL)
+           type = throwable_type_node;
+         eh_type = prepare_eh_table_type (type);
+
+         x = build_call_expr (built_in_decls[BUILT_IN_EH_POINTER],
+                               1, integer_zero_node);
+         x = build2 (MODIFY_EXPR, void_type_node, exc_obj, x);
+         tsi_link_after (&stmts_i, x, TSI_CONTINUE_LINKING);
+
+         x = build1 (GOTO_EXPR, void_type_node, TREE_VALUE (handler));
+         tsi_link_after (&stmts_i, x, TSI_CONTINUE_LINKING);
+
+         x = build2 (CATCH_EXPR, void_type_node, eh_type, stmts);
+         tsi_link_after (&catches_i, x, TSI_CONTINUE_LINKING);
+
+         /* Throwable can match anything in Java, and therefore
+            any subsequent handlers are unreachable.  */
+         /* ??? If we're assured of no foreign language exceptions,
+            we'd be better off using NULL as the exception type
+            for the catch.  */
+         if (type == throwable_type_node)
+           break;
+       }
+
+      body = get_stmts ();
+      *body = build2 (TRY_CATCH_EXPR, void_type_node, *body, catches);
     }
+
 #if defined(DEBUG_JAVA_BINDING_LEVELS)
   indent ();
   fprintf (stderr, "expand end handler pc %d <-- %d\n",
index 29027eb..8ffe242 100644 (file)
@@ -714,6 +714,8 @@ union GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"),
 /* List of checked thrown exceptions, as specified with the `throws'
    keyword */
 #define DECL_FUNCTION_THROWS(DECL) (DECL_LANG_SPECIFIC(DECL)->u.f.throws_list)
+/* VAR_DECL containing the caught exception object.  */
+#define DECL_FUNCTION_EXC_OBJ(DECL) (DECL_LANG_SPECIFIC(DECL)->u.f.exc_obj)
 /* For each function decl, init_test_table contains a hash table whose
    entries are keyed on class names, and whose values are local
    boolean decls.  The variables are intended to be TRUE when the
@@ -785,6 +787,7 @@ struct GTY(()) lang_decl_func {
   int arg_slot_count;
   source_location last_line;   /* End line number for a function decl */
   tree throws_list;            /* Exception specified by `throws' */
+  tree exc_obj;                        /* Decl holding the exception object.  */
 
   /* Class initialization test variables  */
   htab_t GTY ((param_is (struct treetreehash_entry))) init_test_table;
index 997ecb0..d3e69e3 100644 (file)
@@ -30,7 +30,6 @@ enum libfunc_index
   LTI_memset,
   LTI_setbits,
 
-  LTI_unwind_resume,
   LTI_setjmp,
   LTI_longjmp,
   LTI_unwind_sjlj_register,
@@ -59,7 +58,6 @@ extern GTY(()) rtx libfunc_table[LTI_MAX];
 #define memset_libfunc (libfunc_table[LTI_memset])
 #define setbits_libfunc        (libfunc_table[LTI_setbits])
 
-#define unwind_resume_libfunc  (libfunc_table[LTI_unwind_resume])
 #define setjmp_libfunc (libfunc_table[LTI_setjmp])
 #define longjmp_libfunc        (libfunc_table[LTI_longjmp])
 #define unwind_sjlj_register_libfunc (libfunc_table[LTI_unwind_sjlj_register])
index 3ff20eb..3ce714b 100644 (file)
@@ -559,30 +559,6 @@ adjust_decomposed_uses (rtx *px, void *data ATTRIBUTE_UNUSED)
   return 0;
 }
 
-/* We are deleting INSN.  Move any EH_REGION notes to INSNS.  */
-
-static void
-move_eh_region_note (rtx insn, rtx insns)
-{
-  rtx note, p;
-
-  note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
-  if (note == NULL_RTX)
-    return;
-
-  gcc_assert (CALL_P (insn)
-             || (flag_non_call_exceptions && may_trap_p (PATTERN (insn))));
-
-  for (p = insns; p != NULL_RTX; p = NEXT_INSN (p))
-    {
-      if (CALL_P (p)
-         || (flag_non_call_exceptions
-             && INSN_P (p)
-             && may_trap_p (PATTERN (p))))
-       add_reg_note (p, REG_EH_REGION, XEXP (note, 0));
-    }
-}
-
 /* Resolve any decomposed registers which appear in register notes on
    INSN.  */
 
@@ -847,7 +823,7 @@ resolve_simple_move (rtx set, rtx insn)
   insns = get_insns ();
   end_sequence ();
 
-  move_eh_region_note (insn, insns);
+  copy_reg_eh_region_note_forward (insn, insns, NULL_RTX);
 
   emit_insn_before (insns, insn);
 
index 59317eb..70f841b 100644 (file)
@@ -1,3 +1,9 @@
+2009-09-14  Richard Henderson  <rth@redhat.com>
+
+       * objc-act.c (objc_init_exceptions): Don't call
+       default_init_unwind_resume_libfunc.
+       (objc_build_exc_ptr): Use __builtin_eh_pointer.
+
 2009-09-13  Richard Guenther  <rguenther@suse.de>
        Rafael Avila de Espindola  <espindola@google.com>
 
index f695431..eac7ff0 100644 (file)
@@ -3475,7 +3475,7 @@ struct objc_try_context
   /* The CATCH_EXPR of an open @catch clause.  */
   tree current_catch;
 
-  /* The VAR_DECL holding the Darwin equivalent of EXC_PTR_EXPR.  */
+  /* The VAR_DECL holding the Darwin equivalent of __builtin_eh_pointer.  */
   tree caught_decl;
   tree stack_decl;
   tree rethrow_decl;
@@ -3510,9 +3510,9 @@ objc_eh_personality (void)
 }
 #endif
 
-/* Build an EXC_PTR_EXPR, or the moral equivalent.  In the case of Darwin,
-   we'll arrange for it to be initialized (and associated with a binding)
-   later.  */
+/* Build __builtin_eh_pointer, or the moral equivalent.  In the case
+   of Darwin, we'll arrange for it to be initialized (and associated
+   with a binding) later.  */
 
 static tree
 objc_build_exc_ptr (void)
@@ -3528,7 +3528,12 @@ objc_build_exc_ptr (void)
       return var;
     }
   else
-    return build0 (EXC_PTR_EXPR, objc_object_type);
+    {
+      tree t;
+      t = built_in_decls[BUILT_IN_EH_POINTER];
+      t = build_call_expr (t, 1, integer_zero_node);
+      return fold_convert (objc_object_type, t);
+    }
 }
 
 /* Build "objc_exception_try_exit(&_stack)".  */
index a7de367..5cd9463 100644 (file)
@@ -1214,7 +1214,7 @@ new_omp_context (gimple stmt, omp_context *outer_ctx)
       ctx->cb.dst_node = ctx->cb.src_node;
       ctx->cb.src_cfun = cfun;
       ctx->cb.copy_decl = omp_copy_decl;
-      ctx->cb.eh_region = -1;
+      ctx->cb.eh_lp_nr = 0;
       ctx->cb.transform_call_graph_edges = CB_CGE_MOVE;
       ctx->depth = 1;
     }
@@ -3114,23 +3114,22 @@ expand_task_call (basic_block bb, gimple entry_stmt)
 static gimple_seq
 maybe_catch_exception (gimple_seq body)
 {
-  gimple f, t;
+  gimple g;
+  tree decl;
 
   if (!flag_exceptions)
     return body;
 
   if (lang_protect_cleanup_actions)
-    t = lang_protect_cleanup_actions ();
+    decl = lang_protect_cleanup_actions ();
   else
-    t = gimple_build_call (built_in_decls[BUILT_IN_TRAP], 0);
+    decl = built_in_decls[BUILT_IN_TRAP];
 
-  f = gimple_build_eh_filter (NULL, gimple_seq_alloc_with_stmt (t));
-  gimple_eh_filter_set_must_not_throw (f, true);
-
-  t = gimple_build_try (body, gimple_seq_alloc_with_stmt (f),
+  g = gimple_build_eh_must_not_throw (decl);
+  g = gimple_build_try (body, gimple_seq_alloc_with_stmt (g),
                        GIMPLE_TRY_CATCH);
 
- return gimple_seq_alloc_with_stmt (t);
+ return gimple_seq_alloc_with_stmt (g);
 }
 
 /* Chain all the DECLs in LIST by their TREE_CHAIN fields.  */
@@ -6244,7 +6243,7 @@ create_task_copyfn (gimple task_stmt, omp_context *ctx)
       tcctx.cb.dst_node = tcctx.cb.src_node;
       tcctx.cb.src_cfun = ctx->cb.src_cfun;
       tcctx.cb.copy_decl = task_copyfn_copy_decl;
-      tcctx.cb.eh_region = -1;
+      tcctx.cb.eh_lp_nr = 0;
       tcctx.cb.transform_call_graph_edges = CB_CGE_MOVE;
       tcctx.cb.decl_map = pointer_map_create ();
       tcctx.ctx = ctx;
index 35f95f2..a1adc58 100644 (file)
@@ -3858,32 +3858,31 @@ emit_libcall_block (rtx insns, rtx target, rtx result, rtx equiv)
 
   /* If we're using non-call exceptions, a libcall corresponding to an
      operation that may trap may also trap.  */
+  /* ??? See the comment in front of make_reg_eh_region_note.  */
   if (flag_non_call_exceptions && may_trap_p (equiv))
     {
       for (insn = insns; insn; insn = NEXT_INSN (insn))
        if (CALL_P (insn))
          {
            rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
-
-           if (note != 0 && INTVAL (XEXP (note, 0)) <= 0)
-             remove_note (insn, note);
+           if (note)
+             {
+               int lp_nr = INTVAL (XEXP (note, 0));
+               if (lp_nr == 0 || lp_nr == INT_MIN)
+                 remove_note (insn, note);
+             }
          }
     }
   else
-  /* look for any CALL_INSNs in this sequence, and attach a REG_EH_REGION
-     reg note to indicate that this call cannot throw or execute a nonlocal
-     goto (unless there is already a REG_EH_REGION note, in which case
-     we update it).  */
-    for (insn = insns; insn; insn = NEXT_INSN (insn))
-      if (CALL_P (insn))
-       {
-         rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
-
-         if (note != 0)
-           XEXP (note, 0) = constm1_rtx;
-         else
-           add_reg_note (insn, REG_EH_REGION, constm1_rtx);
-       }
+    {
+      /* Look for any CALL_INSNs in this sequence, and attach a REG_EH_REGION
+        reg note to indicate that this call cannot throw or execute a nonlocal
+        goto (unless there is already a REG_EH_REGION note, in which case
+        we update it).  */
+      for (insn = insns; insn; insn = NEXT_INSN (insn))
+       if (CALL_P (insn))
+         make_reg_eh_region_note_nothrow_nononlocal (insn);
+    }
 
   /* First emit all insns that set pseudos.  Remove them from the list as
      we go.  Avoid insns that set pseudos which were referenced in previous
index 531dc60..fa2de03 100644 (file)
@@ -590,6 +590,7 @@ init_optimization_passes (void)
   /* These passes are run after IPA passes on every function that is being
      output to the assembler file.  */
   p = &all_passes;
+  NEXT_PASS (pass_lower_eh_dispatch);
   NEXT_PASS (pass_all_optimizations);
     {
       struct opt_pass **p = &pass_all_optimizations.pass.sub;
@@ -713,6 +714,7 @@ init_optimization_passes (void)
       NEXT_PASS (pass_local_pure_const);
     }
   NEXT_PASS (pass_cleanup_eh);
+  NEXT_PASS (pass_lower_resx);
   NEXT_PASS (pass_nrv);
   NEXT_PASS (pass_mudflap_2);
   NEXT_PASS (pass_cleanup_cfg_post_optimizing);
index 26f467c..1d66769 100644 (file)
@@ -393,6 +393,8 @@ print_node (FILE *file, const char *prefix, tree node, int indent)
 
       if (code == LABEL_DECL && DECL_ERROR_ISSUED (node))
        fputs (" error-issued", file);
+      if (code == LABEL_DECL && EH_LANDING_PAD_NR (node))
+       fprintf (file, " landing-pad:%d", EH_LANDING_PAD_NR (node));
 
       if (code == VAR_DECL && DECL_IN_TEXT_SECTION (node))
        fputs (" in-text-section", file);
index c1e25d7..bfca43b 100644 (file)
@@ -3234,37 +3234,35 @@ peephole2_optimize (void)
                        if (eh_edge->flags & (EDGE_EH | EDGE_ABNORMAL_CALL))
                          break;
 
-                     for (x = attempt ; x != before_try ; x = PREV_INSN (x))
-                       if (CALL_P (x)
-                           || (flag_non_call_exceptions
-                               && may_trap_p (PATTERN (x))
-                               && !find_reg_note (x, REG_EH_REGION, NULL)))
-                         {
-                           if (note)
-                             add_reg_note (x, REG_EH_REGION, XEXP (note, 0));
-
-                           if (x != BB_END (bb) && eh_edge)
-                             {
-                               edge nfte, nehe;
-                               int flags;
-
-                               nfte = split_block (bb, x);
-                               flags = (eh_edge->flags
-                                        & (EDGE_EH | EDGE_ABNORMAL));
-                               if (CALL_P (x))
-                                 flags |= EDGE_ABNORMAL_CALL;
-                               nehe = make_edge (nfte->src, eh_edge->dest,
-                                                 flags);
-
-                               nehe->probability = eh_edge->probability;
-                               nfte->probability
-                                 = REG_BR_PROB_BASE - nehe->probability;
-
-                               do_cleanup_cfg |= purge_dead_edges (nfte->dest);
-                               bb = nfte->src;
-                               eh_edge = nehe;
-                             }
-                         }
+                     if (note)
+                       copy_reg_eh_region_note_backward (note, attempt,
+                                                         before_try);
+
+                     if (eh_edge)
+                       for (x = attempt ; x != before_try ; x = PREV_INSN (x))
+                         if (x != BB_END (bb)
+                             && (can_throw_internal (x)
+                                 || can_nonlocal_goto (x)))
+                           {
+                             edge nfte, nehe;
+                             int flags;
+
+                             nfte = split_block (bb, x);
+                             flags = (eh_edge->flags
+                                      & (EDGE_EH | EDGE_ABNORMAL));
+                             if (CALL_P (x))
+                               flags |= EDGE_ABNORMAL_CALL;
+                             nehe = make_edge (nfte->src, eh_edge->dest,
+                                               flags);
+
+                             nehe->probability = eh_edge->probability;
+                             nfte->probability
+                               = REG_BR_PROB_BASE - nehe->probability;
+
+                             do_cleanup_cfg |= purge_dead_edges (nfte->dest);
+                             bb = nfte->src;
+                             eh_edge = nehe;
+                           }
 
                      /* Converting possibly trapping insn to non-trapping is
                         possible.  Zap dummy outgoing edges.  */
index d5cd37c..984913a 100644 (file)
@@ -447,7 +447,6 @@ static rtx inc_for_reload (rtx, rtx, rtx, int);
 #ifdef AUTO_INC_DEC
 static void add_auto_inc_notes (rtx, rtx);
 #endif
-static void copy_eh_notes (rtx, rtx);
 static void substitute (rtx *, const_rtx, rtx);
 static bool gen_reload_chain_without_interm_reg_p (int, int);
 static int reloads_conflict (int, int);
@@ -4132,17 +4131,11 @@ static void
 fixup_eh_region_note (rtx insn, rtx prev, rtx next)
 {
   rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
-  rtx i;
-
   if (note == NULL)
     return;
-
-  if (! may_trap_p (PATTERN (insn)))
+  if (!insn_could_throw_p (insn))
     remove_note (insn, note);
-
-  for (i = NEXT_INSN (prev); i != next; i = NEXT_INSN (i))
-    if (INSN_P (i) && i != insn && may_trap_p (PATTERN (i)))
-      add_reg_note (i, REG_EH_REGION, XEXP (note, 0));
+  copy_reg_eh_region_note_forward (note, NEXT_INSN (prev), next);
 }
 
 /* Reload pseudo-registers into hard regs around each insn as needed.
@@ -7294,7 +7287,7 @@ emit_input_reload_insns (struct insn_chain *chain, struct reload *rl,
     }