]> gcc.gnu.org Git - gcc.git/commitdiff
Squash commit of EH in gimple
authorRichard Henderson <rth@redhat.com>
Mon, 14 Sep 2009 19:18:58 +0000 (12:18 -0700)
committerRichard Henderson <rth@gcc.gnu.org>
Mon, 14 Sep 2009 19:18:58 +0000 (12:18 -0700)
From-SVN: r151696

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 75333c13f38a3bafd4f91deb96a856a1480f0ae9..cc048311c99e715cd36412c9cdef1374a913198f 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 d89fb2a7e8c3e2833a54041cd3246f1862c81d53..2e406b6c63af2b772ded7ee64316b1bbf27c467d 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 368d494a67be8b239252336486d01501d085cf84..5747227dc2b1032958286d2a6e9ab0183a51a005 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 261351f840c917813e56f0f240a03956e5a7817d..26df68de581261d289d95bb346083bfcb4e0a1b8 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 29ab72a365f46a140465a543971ba2cf57a709db..61a3aea8c689ccf347db7574cb1156183e833ad0 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 9748caf546335fc5e91b75bf8cd9157262871cee..bd6a840b2455ee74b8c92d388b54ac623bb37baf 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 d4801b14e55dc06a8fc0b43f1199b04a5cb5a327..ee6417d61d6fdef3106be465e3de05d5ff7819fc 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 8d1693605a6dd7fbc45471d41f09676062be7026..00287c7548a1e3d758378c927924f165a86928f3 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 a19489c49df99312fd7c4475ff0f26a51398e803..25c0c0137d1a0bbe8ac68d691768ec810a4954fb 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 ddb81e16504e97037ae60f9753e3f390bfd0edcc..feec8a4e6240cbabe51ef66aea74408b3e6996f7 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 20639098e02b3d7f68fde549a10627335b02f3e2..16229cc4defb95390d669a75de47632e1b44a025 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 6e941bf55e9fe5e592b9daae4cddadf52719f5db..7d87a7a184e4ed619871b340014f545cd9abb531 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 d1c2be29b32578439e3ca8daee6bf47bcb04a7bb..0ed6bd5903db5254c309833222185972e472ccb0 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 4c4b3b72cc76acf6de88bb02e613033881c9785d..a7e93dd4c672c91c6716faf1b138aa8750141748 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 5551c721762e41944cd87bd9de16d13f441419a8..2ad07187e04a2fbd163a970afea8fabec6478aed 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 3437216ed51679bba4a91b55856f32c6d4318c67..6b507c2991d1e04fa157bf1511869be3c8a00c98 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 a50e9fcaf25f58b0607670ee6a81206f4923e9d9..4a17a77dbec9a4b057e7190a2aab014528ea3c89 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 588c2ee68d8b7c789e1b3707998a81703cb079f6..1b13819ed67496bc747cddb6b69417e4006b056e 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 abd38f8666cdcd2e62787cb00f777d660a7f49e5..58d5b9001d2646f23bf7b1723a86740adf238e18 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 3f3b863794f1a8122b3c649b8ae397c4c7418aab..8f49a9af9f582131add5300e73b2997f9e89c0ad 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 3e1dd47f3a4b456d9fd618d2f35efb41908b9ac7..b937dd44a190c6af421d9d00c55feac4b8da2a10 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 3e6b57d6ca118fc33755366972f1f3c98c8ca3da..9d3e2c07ed61c3a5b78cfd7b52c90679543843a1 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 65022fc65e31699d2ccf0d3764c146b65bf97178..9ed36b332119f8cbdce46c7d559899059b567bd0 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 9b6c24eff9b7ad332059215bdb25858331c5fc79..c916a18089b9c56f68eeb5b246aa975de906f1dd 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 af63e983a3acbdc92ea4bc7be846dcedea11b51f..3e9a39cbb5f1fd8b960ba2225c2316c4b7de6e98 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 be3b5bb5e5be91bbee3c89e5209e2e03e54275a3..5d18435a99a9af53565aba39e20d7e0b3d15d507 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 342e3760bdf0f524fca78ab0671c6a94c02efdda..1ce0013ef354234f0ea5195a6e88c0d0cbe256eb 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 7cf6e86d9b05a958efac3d9587c3bae2e5601e89..b8586c2c0bc2e930fc7b4a8a5b4d74b47dde24ec 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 3d94fd624240efc8b1743f19b7dc423f49d84709..a21044c64ae48a0de059ef79a5a6dd846a3c5bd3 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 446bc9d82e15b88c181a3de728248a74bdee376b..72aad0006dc54c33818fb1ee2af10eec8fa2474a 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 dc4aa8b9a965eb3fef880e95ea05ef309b4e6bdd..803ab3e5a148a91d4dd3d87c8182f119403a2017 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 1a2f38bd8b5c96c9cba45cbcb3b5a7109022da47..69fa68ddb42e038e92071428feef0c8bebdd8a31 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 876225b8bf981e42b79f301f0eb31a847bedd78c..66927d67c2c88f42b52d968980b9600796bae47e 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 eba86727a0595031c6bd2fd1415d68edc50c5246..b58fd7b42f5f5df9d53ff9be195fc009d290eb21 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 50180203e2d2351e90d956b108de9256341f6956..8903c66195600ecf29faa23021a06fbd2231dd14 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 3be6d843fe21d6f587018fdb4cc589728cd9b1da..33daafc6ad0b7795cb145b53ef5694ea0c38cf42 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 1a3f345e106b3ccc1e45bd59fac7fe48f2189608..603d97eeafc1d2e0ff19cb911eff2324fa9ac066 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 8ca1f288084e8add491f5a98da61b534704fcca1..b5396235f6be4e0bb23fab20d1611ffad2019a22 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 7f1dc4ae94bd861215bea72cdc54c2689d794b2b..381e611bc8f330b3151a327b961a216d2b0a7cde 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 97875c9e03627886b5fcd2159cb95ed4f52aadc4..29cb90d913c65cc456a3b4cc55d653a5afb994ec 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 79de3634d865d37ffbe0803a1b7b6d76d15a1051..c6bbece3ace8107a8063419c96fd0088ce62c953 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 201dc5996c1ef8eb6da5fdc2321ca055d85e664f..e5ff3a7725346121b75c31e7aa92aa44b4585f99 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 62516d0f34c9141c133e7dcb16b540bd0bbcb8ac..edfaab0a0f89668330223bf81925147e8d30b6a2 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 a001916fb0096512fd045bfd25f9719c0839bf9d..0b7ec66ab2c04206d785262aa6d30e82c3284d88 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 6b7d930ba28ae8749e4a73a8d4da2bffa7c05431..6c58a99b4c171869a6d7cd3cc23c95c6397d9117 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 6e4815beeab2755e9e7a4b2b5bb95741c0e9bebe..a05ff53ceb99c93e8922d37809584817e76541f7 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 c9ccc9d8556f329c7f8dcb26033179eb76780899..c593b53df5cef54c1a6c03fb44e1947a7f06a7d1 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 e97ed7755d9298b5fc5971b1e2921ad6a59075d3..4e4651421d491936c3b693e550935ad187d36edc 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 29027eb64637b57f436f256b81bb62f73a38d4b5..8ffe24229678facc66a2279dad1260b89cdabbe9 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 997ecb036414eaff5d5cc69ed804871876c620a0..d3e69e3e2414a0d9808b7aaa3b76921660272686 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 3ff20eb3de52647a18f38515c92d9fbc7c47f5e7..3ce714b2bf8e54a02307c2a752c2c1b6ccabea98 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 59317eb200c16a38cd96985d648d7c4f96c82ae5..70f841be2bacad1c8a0af5daedc16f1937e5f2c7 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 f695431030a57564c28dea2e600368a02f582c7c..eac7ff02f0937de90b8abf12c83453cc0a8b625e 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 a7de367e43285ba7ddb78404df7f261c76c5fee0..5cd9463c1226bbec42fba5c48e2a12409b8f680e 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 35f95f2e3d48b2115273846e36a4b151f5ac4c10..a1adc581dc12462e9fdde3e2b71ff9caa505eaa3 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 531dc602739792ed7a73a0d86ca35e2745700d22..fa2de0376120b72ab33909cd9fea42784922752a 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 26f467cba8e113e2237b4dad3fb061cb6a95ab36..1d66769a1f768ccd03ec8be7833f8996d17b7934 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 c1e25d746a15150039aec6da7bc3f6b20c3b03cb..bfca43b4552564fd8f3cb9913c06e518c55ae6de 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 d5cd37ce0bd09765c0f769ebd5745b5e3ad28ae9..984913a5fc123e6dbd003e4f691f2329a756000b 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,
     }
 
   if (flag_non_call_exceptions)
-    copy_eh_notes (insn, get_insns ());
+    copy_reg_eh_region_note_forward (insn, get_insns (), NULL);
 
   /* End this sequence.  */
   *where = get_insns ();
@@ -7514,7 +7507,7 @@ emit_output_reload_insns (struct insn_chain *chain, struct reload *rl,
     output_reload_insns[rl->opnum] = get_insns ();
 
   if (flag_non_call_exceptions)
-    copy_eh_notes (insn, get_insns ());
+    copy_reg_eh_region_note_forward (insn, get_insns (), NULL);
 
   end_sequence ();
 }
@@ -8890,21 +8883,6 @@ add_auto_inc_notes (rtx insn, rtx x)
 }
 #endif
 
-/* Copy EH notes from an insn to its reloads.  */
-static void
-copy_eh_notes (rtx insn, rtx x)
-{
-  rtx eh_note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
-  if (eh_note)
-    {
-      for (; x != 0; x = NEXT_INSN (x))
-       {
-         if (may_trap_p (PATTERN (x)))
-           add_reg_note (x, REG_EH_REGION, XEXP (eh_note, 0));
-       }
-    }
-}
-
 /* This is used by reload pass, that does emit some instructions after
    abnormal calls moving basic block end, but in fact it wants to emit
    them on the edge.  Looks for abnormal call edges, find backward the
index bcb5cbcd9b0523f70b52b5e4b84fe3883e8d5dd3..d1c079353d3e7fe34faae3b37a33c229484f46b2 100644 (file)
@@ -301,11 +301,6 @@ DEF_RTL_EXPR(EH_RETURN, "eh_return", "", RTX_EXTRA)
    For an unconditional trap, make the condition (const_int 1).  */
 DEF_RTL_EXPR(TRAP_IF, "trap_if", "ee", RTX_EXTRA)
 
-/* Placeholder for _Unwind_Resume before we know if a function call
-   or a branch is needed.  Operand 1 is the exception region from
-   which control is flowing.  */
-DEF_RTL_EXPR(RESX, "resx", "i", RTX_EXTRA)
-
 /* ----------------------------------------------------------------------
    Primitive values for use in expressions.
    ---------------------------------------------------------------------- */
index 3427347225d1d04118c50e0b542027fe09283de4..d3acebe5f571069e343645bc92a9702dd4aebb1b 100644 (file)
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -1841,6 +1841,13 @@ extern int volatile_insn_p (const_rtx);
 extern int may_trap_p_1 (const_rtx, unsigned);
 extern int may_trap_p (const_rtx);
 extern int may_trap_or_fault_p (const_rtx);
+extern bool can_throw_internal (const_rtx);
+extern bool can_throw_external (const_rtx);
+extern bool insn_could_throw_p (const_rtx);
+extern bool insn_nothrow_p (const_rtx);
+extern bool can_nonlocal_goto (const_rtx);
+extern void copy_reg_eh_region_note_forward (rtx, rtx, rtx);
+extern void copy_reg_eh_region_note_backward(rtx, rtx, rtx);
 extern int inequality_comparisons_p (const_rtx);
 extern rtx replace_rtx (rtx, rtx, rtx);
 extern int replace_label (rtx *, void *);
index 394d465f098732e63a5946043b4a63788e0bfcf1..e2c9eb8848f4fcfb1c6f43afd37ccac51408cd2a 100644 (file)
@@ -1186,7 +1186,6 @@ graphite_copy_stmts_from_block (basic_block bb, basic_block new_bb, htab_t map)
     {
       def_operand_p def_p;
       ssa_op_iter op_iter;
-      int region;
       gimple stmt = gsi_stmt (gsi);
       gimple copy;
 
@@ -1199,9 +1198,7 @@ graphite_copy_stmts_from_block (basic_block bb, basic_block new_bb, htab_t map)
       gsi_insert_after (&gsi_tgt, copy, GSI_NEW_STMT);
       mark_sym_for_renaming (gimple_vop (cfun));
 
-      region = lookup_stmt_eh_region (stmt);
-      if (region >= 0)
-       add_stmt_to_eh_region (copy, region);
+      maybe_duplicate_eh_stmt (copy, stmt);
       gimple_duplicate_stmt_histograms (cfun, copy, cfun, stmt);
 
       /* Create new names for all the definitions created by COPY and
index 23e9dbf5b025f2e843cc1b4a00db8c8b20fad16d..db86cf687401be2aacfd4b7569c332a86d7861d2 100644 (file)
@@ -1,3 +1,8 @@
+2009-09-14  Richard Henderson  <rth@redhat.com>
+
+       * g++.dg/eh/builtin1.C: Update resx pattern match.
+       * g++.dg/eh/builtin2.C, g++.dg/eh/builtin3.C: Likewise.
+
 2009-09-14  Richard Sandiford  <rdsandiford@googlemail.com>
 
        * gcc.target/mips/branch-helper.h: New file.
index 1f56d1a833dd3e17cb8d3731617de395c570ecd8..ed49e9a962a034d235d136fb2d812295adb794e5 100644 (file)
@@ -22,5 +22,5 @@ bar ()
   __builtin_printf ("foo %d\n", a.i);
 }
 
-/* { dg-final { scan-tree-dump-times "resx 1" 2 "eh" } } */
+/* { dg-final { scan-tree-dump-times "resx" 2 "eh" } } */
 /* { dg-final { cleanup-tree-dump "eh" } } */
index b106516da683866ff3692779346c69cf46de8f52..fe0c4de6b3eb51a124331be5b7fad136002d66b1 100644 (file)
@@ -21,5 +21,5 @@ bar ()
   __builtin_printf ("foo %d\n", a.i);
 }
 
-/* { dg-final { scan-tree-dump-times "resx 1" 0 "eh" } } */
+/* { dg-final { scan-tree-dump-times "resx" 0 "eh" } } */
 /* { dg-final { cleanup-tree-dump "eh" } } */
index be1629ea5f85b8dd2331f4b5bd50655303d0a2a8..45809b81553771acac1e662e35c36de17fab176e 100644 (file)
@@ -12,5 +12,5 @@ bar ()
   __builtin_printf ("foo %d\n", a.i);
 }
 
-/* { dg-final { scan-tree-dump-times "resx 1" 1 "eh" } } */
+/* { dg-final { scan-tree-dump-times "resx" 1 "eh" } } */
 /* { dg-final { cleanup-tree-dump "eh" } } */
index 3de72aac590e069475e447ff1d09a54d87f69f79..8dfaa52b6bb7b684fdad8b4e218a308dc701d9af 100644 (file)
@@ -19,6 +19,6 @@ t (void)
 // { dg-final { scan-tree-dump-times "Empty EH handler" 1 "ehcleanup1" } }
 //
 // And as a result also contained control flow.
-// { dg-final { scan-tree-dump-times "Removing unreachable" 1 "ehcleanup1" } }
+// { dg-final { scan-tree-dump-times "Removing unreachable" 2 "ehcleanup1" } }
 //
 // { dg-final { cleanup-tree-dump "ehcleanup1" } }
index 02daee092efdb14f3d5efd0899c5b8eeaf15c699..fb24cc48a4a521175e261033cc355960a7e0204a 100644 (file)
@@ -545,6 +545,9 @@ make_edges (void)
              make_eh_edges (last);
              fallthru = false;
              break;
+           case GIMPLE_EH_DISPATCH:
+             fallthru = make_eh_dispatch_edges (last);
+             break;
 
            case GIMPLE_CALL:
              /* If this function receives a nonlocal goto, then we need to
@@ -565,9 +568,7 @@ make_edges (void)
               /* A GIMPLE_ASSIGN may throw internally and thus be considered
                  control-altering. */
              if (is_ctrl_altering_stmt (last))
-               {
-                 make_eh_edges (last);
-               }
+               make_eh_edges (last);
              fallthru = true;
              break;
 
@@ -1033,29 +1034,6 @@ static struct label_record
   bool used;
 } *label_for_bb;
 
-/* Callback for for_each_eh_region.  Helper for cleanup_dead_labels.  */
-static void
-update_eh_label (struct eh_region_d *region)
-{
-  tree old_label = get_eh_region_tree_label (region);
-  if (old_label)
-    {
-      tree new_label;
-      basic_block bb = label_to_block (old_label);
-
-      /* ??? After optimizing, there may be EH regions with labels
-        that have already been removed from the function body, so
-        there is no basic block for them.  */
-      if (! bb)
-       return;
-
-      new_label = label_for_bb[bb->index].label;
-      label_for_bb[bb->index].used = true;
-      set_eh_region_tree_label (region, new_label);
-    }
-}
-
-
 /* Given LABEL return the first label in the same basic block.  */
 
 static tree
@@ -1075,6 +1053,58 @@ main_block_label (tree label)
   return main_label;
 }
 
+/* Clean up redundant labels within the exception tree.  */
+
+static void
+cleanup_dead_labels_eh (void)
+{
+  eh_landing_pad lp;
+  eh_region r;
+  tree lab;
+  int i;
+
+  if (cfun->eh == NULL)
+    return;
+
+  for (i = 1; VEC_iterate (eh_landing_pad, cfun->eh->lp_array, i, lp); ++i)
+    if (lp && lp->post_landing_pad)
+      {
+       lab = main_block_label (lp->post_landing_pad);
+       if (lab != lp->post_landing_pad)
+         {
+           EH_LANDING_PAD_NR (lp->post_landing_pad) = 0;
+           EH_LANDING_PAD_NR (lab) = lp->index;
+         }
+      }
+
+  FOR_ALL_EH_REGION (r)
+    switch (r->type)
+      {
+      case ERT_CLEANUP:
+      case ERT_MUST_NOT_THROW:
+       break;
+
+      case ERT_TRY:
+       {
+         eh_catch c;
+         for (c = r->u.eh_try.first_catch; c ; c = c->next_catch)
+           {
+             lab = c->label;
+             if (lab)
+               c->label = main_block_label (lab);
+           }
+       }
+       break;
+
+      case ERT_ALLOWED_EXCEPTIONS:
+       lab = r->u.allowed.label;
+       if (lab)
+         r->u.allowed.label = main_block_label (lab);
+       break;
+      }
+}
+
+
 /* Cleanup redundant labels.  This is a three-step process:
      1) Find the leading label for each block.
      2) Redirect all references to labels to the leading labels.
@@ -1173,7 +1203,8 @@ cleanup_dead_labels (void)
       }
     }
 
-  for_each_eh_region (update_eh_label);
+  /* Do the same for the exception region tree labels.  */
+  cleanup_dead_labels_eh ();
 
   /* Finally, purge dead labels.  All user-defined labels and labels that
      can be the target of non-local gotos and labels which have their
@@ -1584,9 +1615,11 @@ gimple_merge_blocks (basic_block a, basic_block b)
   /* Remove labels from B and set gimple_bb to A for other statements.  */
   for (gsi = gsi_start_bb (b); !gsi_end_p (gsi);)
     {
-      if (gimple_code (gsi_stmt (gsi)) == GIMPLE_LABEL)
+      gimple stmt = gsi_stmt (gsi);
+      if (gimple_code (stmt) == GIMPLE_LABEL)
        {
-         gimple label = gsi_stmt (gsi);
+         tree label = gimple_label_label (stmt);
+         int lp_nr;
 
          gsi_remove (&gsi, false);
 
@@ -1596,15 +1629,22 @@ gimple_merge_blocks (basic_block a, basic_block b)
             used in other ways (think about the runtime checking for
             Fortran assigned gotos).  So we can not just delete the
             label.  Instead we move the label to the start of block A.  */
-         if (FORCED_LABEL (gimple_label_label (label)))
+         if (FORCED_LABEL (label))
            {
              gimple_stmt_iterator dest_gsi = gsi_start_bb (a);
-             gsi_insert_before (&dest_gsi, label, GSI_NEW_STMT);
+             gsi_insert_before (&dest_gsi, stmt, GSI_NEW_STMT);
+           }
+
+         lp_nr = EH_LANDING_PAD_NR (label);
+         if (lp_nr)
+           {
+             eh_landing_pad lp = get_eh_landing_pad_from_number (lp_nr);
+             lp->post_landing_pad = NULL;
            }
        }
       else
        {
-         gimple_set_bb (gsi_stmt (gsi), a);
+         gimple_set_bb (stmt, a);
          gsi_next (&gsi);
        }
     }
@@ -1917,10 +1957,7 @@ remove_useless_stmts_tc (gimple_stmt_iterator *gsi, struct rus_data *data)
       break;
 
     case GIMPLE_EH_FILTER:
-      /* If the first element is an eh_filter, it should stand alone.  */
-      if (gimple_eh_filter_must_not_throw (stmt))
-       this_may_throw = false;
-      else if (gimple_eh_filter_types (stmt) == NULL)
+      if (gimple_eh_filter_types (stmt) == NULL)
        this_may_throw = false;
       failure_seq = gimple_eh_filter_failure (stmt);
       failure_gsi = gsi_start (failure_seq);
@@ -1928,6 +1965,10 @@ remove_useless_stmts_tc (gimple_stmt_iterator *gsi, struct rus_data *data)
       gsi_next (gsi);
       break;
 
+    case GIMPLE_EH_MUST_NOT_THROW:
+      this_may_throw = false;
+      break;
+
     default:
       /* Otherwise this is a list of cleanup statements.  */
       remove_useless_stmts_1 (&cleanup_gsi, data);
@@ -2774,6 +2815,12 @@ is_ctrl_altering_stmt (gimple t)
       }
       break;
 
+    case GIMPLE_EH_DISPATCH:
+      /* EH_DISPATCH branches to the individual catch handlers at
+        this level of a try or allowed-exceptions region.  It can
+        fallthru to the next statement as well.  */
+      return true;
+
     CASE_GIMPLE_OMP:
       /* OpenMP directives alter control flow.  */
       return true;
@@ -4039,8 +4086,6 @@ verify_gimple_assign_single (gimple stmt)
     case OBJ_TYPE_REF:
     case ASSERT_EXPR:
     case WITH_SIZE_EXPR:
-    case EXC_PTR_EXPR:
-    case FILTER_EXPR:
     case POLYNOMIAL_CHREC:
     case DOT_PROD_EXPR:
     case VEC_COND_EXPR:
@@ -4248,8 +4293,9 @@ verify_types_in_gimple_stmt (gimple stmt)
 
     /* Tuples that do not have tree operands.  */
     case GIMPLE_NOP:
-    case GIMPLE_RESX:
     case GIMPLE_PREDICT:
+    case GIMPLE_RESX:
+    case GIMPLE_EH_DISPATCH:
       return false;
 
     CASE_GIMPLE_OMP:
@@ -4334,6 +4380,7 @@ verify_stmt (gimple_stmt_iterator *gsi)
   struct walk_stmt_info wi;
   bool last_in_block = gsi_one_before_end_p (*gsi);
   gimple stmt = gsi_stmt (*gsi);
+  int lp_nr;
 
   if (is_gimple_omp (stmt))
     {
@@ -4388,17 +4435,21 @@ verify_stmt (gimple_stmt_iterator *gsi)
      have optimizations that simplify statements such that we prove
      that they cannot throw, that we update other data structures
      to match.  */
-  if (lookup_stmt_eh_region (stmt) >= 0)
+  lp_nr = lookup_stmt_eh_lp (stmt);
+  if (lp_nr != 0)
     {
-      /* During IPA passes, ipa-pure-const sets nothrow flags on calls
-         and they are updated on statements only after fixup_cfg
-        is executed at beggining of expansion stage.  */
-      if (!stmt_could_throw_p (stmt) && cgraph_state != CGRAPH_STATE_IPA_SSA)
+      if (!stmt_could_throw_p (stmt))
        {
-         error ("statement marked for throw, but doesn%'t");
-         goto fail;
+         /* During IPA passes, ipa-pure-const sets nothrow flags on calls
+            and they are updated on statements only after fixup_cfg
+            is executed at beggining of expansion stage.  */
+         if (cgraph_state != CGRAPH_STATE_IPA_SSA)
+           {
+             error ("statement marked for throw, but doesn%'t");
+             goto fail;
+           }
        }
-      if (!last_in_block && stmt_can_throw_internal (stmt))
+      else if (lp_nr > 0 && !last_in_block && stmt_can_throw_internal (stmt))
        {
          error ("statement marked for throw in middle of block");
          goto fail;
@@ -4586,9 +4637,20 @@ verify_stmts (void)
              if (uid == -1
                  || VEC_index (basic_block, label_to_block_map, uid) != bb)
                {
-                 error ("incorrect entry in label_to_block_map.\n");
+                 error ("incorrect entry in label_to_block_map");
                  err |= true;
                }
+
+             uid = EH_LANDING_PAD_NR (decl);
+             if (uid)
+               {
+                 eh_landing_pad lp = get_eh_landing_pad_from_number (uid);
+                 if (decl != lp->post_landing_pad)
+                   {
+                     error ("incorrect setting of landing pad number");
+                     err |= true;
+                   }
+               }
            }
 
          err |= verify_stmt (&gsi);
@@ -4735,6 +4797,9 @@ gimple_verify_flow_info (void)
 
       stmt = gsi_stmt (gsi);
 
+      if (gimple_code (stmt) == GIMPLE_LABEL)
+       continue;
+
       err |= verify_eh_edges (stmt);
 
       if (is_ctrl_stmt (stmt))
@@ -4904,8 +4969,14 @@ gimple_verify_flow_info (void)
            FOR_EACH_EDGE (e, ei, bb->succs)
              e->dest->aux = (void *)0;
          }
+         break;
+
+       case GIMPLE_EH_DISPATCH:
+         err |= verify_eh_dispatch_edge (stmt);
+         break;
 
-       default: ;
+       default:
+         break;
        }
     }
 
@@ -5129,6 +5200,11 @@ gimple_redirect_edge_and_branch (edge e, basic_block dest)
       /* The edges from OMP constructs can be simply redirected.  */
       break;
 
+    case GIMPLE_EH_DISPATCH:
+      if (!(e->flags & EDGE_FALLTHRU))
+       redirect_eh_dispatch_edge (stmt, e, dest);
+      break;
+
     default:
       /* Otherwise it must be a fallthru edge, and we don't need to
         do anything besides redirecting it.  */
@@ -5278,7 +5354,6 @@ gimple_duplicate_bb (basic_block bb)
     {
       def_operand_p def_p;
       ssa_op_iter op_iter;
-      int region;
 
       stmt = gsi_stmt (gsi);
       if (gimple_code (stmt) == GIMPLE_LABEL)
@@ -5288,9 +5363,8 @@ gimple_duplicate_bb (basic_block bb)
         operands.  */
       copy = gimple_copy (stmt);
       gsi_insert_after (&gsi_tgt, copy, GSI_NEW_STMT);
-      region = lookup_stmt_eh_region (stmt);
-      if (region >= 0)
-       add_stmt_to_eh_region (copy, region);
+
+      maybe_duplicate_eh_stmt (copy, stmt);
       gimple_duplicate_stmt_histograms (cfun, copy, cfun, stmt);
 
       /* Create new names for all the definitions created by COPY and
@@ -5818,6 +5892,7 @@ struct move_stmt_d
   tree to_context;
   struct pointer_map_t *vars_map;
   htab_t new_label_map;
+  struct pointer_map_t *eh_map;
   bool remap_decls_p;
 };
 
@@ -5883,6 +5958,35 @@ move_stmt_op (tree *tp, int *walk_subtrees, void *data)
   return NULL_TREE;
 }
 
+/* Helper for move_stmt_r.  Given an EH region number for the source
+   function, map that to the duplicate EH regio number in the dest.  */
+
+static int
+move_stmt_eh_region_nr (int old_nr, struct move_stmt_d *p)
+{
+  eh_region old_r, new_r;
+  void **slot;
+
+  old_r = get_eh_region_from_number (old_nr);
+  slot = pointer_map_contains (p->eh_map, old_r);
+  new_r = (eh_region) *slot;
+
+  return new_r->index;
+}
+
+/* Similar, but operate on INTEGER_CSTs.  */
+
+static tree
+move_stmt_eh_region_tree_nr (tree old_t_nr, struct move_stmt_d *p)
+{
+  int old_nr, new_nr;
+
+  old_nr = tree_low_cst (old_t_nr, 0);
+  new_nr = move_stmt_eh_region_nr (old_nr, p);
+
+  return build_int_cst (NULL, new_nr);
+}
+
 /* Like move_stmt_op, but for gimple statements.
 
    Helper for move_block_to_fn.  Set GIMPLE_BLOCK in every expression
@@ -5911,21 +6015,70 @@ move_stmt_r (gimple_stmt_iterator *gsi_p, bool *handled_ops_p,
     }
 #endif
 
-  if (is_gimple_omp (stmt)
-      && gimple_code (stmt) != GIMPLE_OMP_RETURN
-      && gimple_code (stmt) != GIMPLE_OMP_CONTINUE)
+  switch (gimple_code (stmt))
     {
-      /* Do not remap variables inside OMP directives.  Variables
-        referenced in clauses and directive header belong to the
-        parent function and should not be moved into the child
-        function.  */
-      bool save_remap_decls_p = p->remap_decls_p;
-      p->remap_decls_p = false;
-      *handled_ops_p = true;
+    case GIMPLE_CALL:
+      /* Remap the region numbers for __builtin_eh_{pointer,filter}.  */
+      {
+       tree r, fndecl = gimple_call_fndecl (stmt);
+       if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
+         switch (DECL_FUNCTION_CODE (fndecl))
+           {
+           case BUILT_IN_EH_COPY_VALUES:
+             r = gimple_call_arg (stmt, 1);
+             r = move_stmt_eh_region_tree_nr (r, p);
+             gimple_call_set_arg (stmt, 1, r);
+             /* FALLTHRU */
+
+           case BUILT_IN_EH_POINTER:
+           case BUILT_IN_EH_FILTER:
+             r = gimple_call_arg (stmt, 0);
+             r = move_stmt_eh_region_tree_nr (r, p);
+             gimple_call_set_arg (stmt, 0, r);
+             break;
 
-      walk_gimple_seq (gimple_omp_body (stmt), move_stmt_r, move_stmt_op, wi);
+           default:
+             break;
+           }
+      }
+      break;
+
+    case GIMPLE_RESX:
+      {
+       int r = gimple_resx_region (stmt);
+       r = move_stmt_eh_region_nr (r, p);
+       gimple_resx_set_region (stmt, r);
+      }
+      break;
 
-      p->remap_decls_p = save_remap_decls_p;
+    case GIMPLE_EH_DISPATCH:
+      {
+       int r = gimple_eh_dispatch_region (stmt);
+       r = move_stmt_eh_region_nr (r, p);
+       gimple_eh_dispatch_set_region (stmt, r);
+      }
+      break;
+
+    case GIMPLE_OMP_RETURN:
+    case GIMPLE_OMP_CONTINUE:
+      break;
+    default:
+      if (is_gimple_omp (stmt))
+       {
+         /* Do not remap variables inside OMP directives.  Variables
+            referenced in clauses and directive header belong to the
+            parent function and should not be moved into the child
+            function.  */
+         bool save_remap_decls_p = p->remap_decls_p;
+         p->remap_decls_p = false;
+         *handled_ops_p = true;
+
+         walk_gimple_seq (gimple_omp_body (stmt), move_stmt_r,
+                          move_stmt_op, wi);
+
+         p->remap_decls_p = save_remap_decls_p;
+       }
+      break;
     }
 
   return NULL_TREE;
@@ -5959,7 +6112,7 @@ mark_virtual_ops_in_bb (basic_block bb)
 static void
 move_block_to_fn (struct function *dest_cfun, basic_block bb,
                  basic_block after, bool update_edge_count_p,
-                 struct move_stmt_d *d, int eh_offset)
+                 struct move_stmt_d *d)
 {
   struct control_flow_graph *cfg;
   edge_iterator ei;
@@ -6035,7 +6188,6 @@ move_block_to_fn (struct function *dest_cfun, basic_block bb,
   for (si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si))
     {
       gimple stmt = gsi_stmt (si);
-      int region;
       struct walk_stmt_info wi;
 
       memset (&wi, 0, sizeof (wi));
@@ -6065,17 +6217,12 @@ move_block_to_fn (struct function *dest_cfun, basic_block bb,
          if (uid >= dest_cfun->cfg->last_label_uid)
            dest_cfun->cfg->last_label_uid = uid + 1;
        }
-      else if (gimple_code (stmt) == GIMPLE_RESX && eh_offset != 0)
-       gimple_resx_set_region (stmt, gimple_resx_region (stmt) + eh_offset);
 
-      region = lookup_stmt_eh_region (stmt);
-      if (region >= 0)
-       {
-         add_stmt_to_eh_region_fn (dest_cfun, stmt, region + eh_offset);
-         remove_stmt_from_eh_region (stmt);
-         gimple_duplicate_stmt_histograms (dest_cfun, stmt, cfun, stmt);
-          gimple_remove_stmt_histograms (cfun, stmt);
-       }
+      maybe_duplicate_eh_stmt_fn (dest_cfun, stmt, cfun, stmt, d->eh_map, 0);
+      remove_stmt_from_eh_lp_fn (cfun, stmt);
+
+      gimple_duplicate_stmt_histograms (dest_cfun, stmt, cfun, stmt);
+      gimple_remove_stmt_histograms (cfun, stmt);
 
       /* We cannot leave any operands allocated from the operand caches of
         the current function.  */
@@ -6106,29 +6253,28 @@ move_block_to_fn (struct function *dest_cfun, basic_block bb,
 /* Examine the statements in BB (which is in SRC_CFUN); find and return
    the outermost EH region.  Use REGION as the incoming base EH region.  */
 
-static int
+static eh_region
 find_outermost_region_in_block (struct function *src_cfun,
-                               basic_block bb, int region)
+                               basic_block bb, eh_region region)
 {
   gimple_stmt_iterator si;
 
   for (si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si))
     {
       gimple stmt = gsi_stmt (si);
-      int stmt_region;
+      eh_region stmt_region;
+      int lp_nr;
 
-      if (gimple_code (stmt) == GIMPLE_RESX)
-       stmt_region = gimple_resx_region (stmt);
-      else
-       stmt_region = lookup_stmt_eh_region_fn (src_cfun, stmt);
-      if (stmt_region > 0)
+      lp_nr = lookup_stmt_eh_lp_fn (src_cfun, stmt);
+      stmt_region = get_eh_region_from_lp_number_fn (src_cfun, lp_nr);
+      if (stmt_region)
        {
-         if (region < 0)
+         if (region == NULL)
            region = stmt_region;
          else if (stmt_region != region)
            {
              region = eh_region_outermost (src_cfun, stmt_region, region);
-             gcc_assert (region != -1);
+             gcc_assert (region != NULL);
            }
        }
     }
@@ -6218,13 +6364,13 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
   basic_block dom_entry = get_immediate_dominator (CDI_DOMINATORS, entry_bb);
   basic_block after, bb, *entry_pred, *exit_succ, abb;
   struct function *saved_cfun = cfun;
-  int *entry_flag, *exit_flag, eh_offset;
+  int *entry_flag, *exit_flag;
   unsigned *entry_prob, *exit_prob;
   unsigned i, num_entry_edges, num_exit_edges;
   edge e;
   edge_iterator ei;
   htab_t new_label_map;
-  struct pointer_map_t *vars_map;
+  struct pointer_map_t *vars_map, *eh_map;
   struct loop *loop = entry_bb->loop_father;
   struct move_stmt_d d;
 
@@ -6294,21 +6440,21 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
   init_empty_tree_cfg ();
 
   /* Initialize EH information for the new function.  */
-  eh_offset = 0;
+  eh_map = NULL;
   new_label_map = NULL;
   if (saved_cfun->eh)
     {
-      int region = -1;
+      eh_region region = NULL;
 
       for (i = 0; VEC_iterate (basic_block, bbs, i, bb); i++)
        region = find_outermost_region_in_block (saved_cfun, bb, region);
 
       init_eh_for_function ();
-      if (region != -1)
+      if (region != NULL)
        {
          new_label_map = htab_create (17, tree_map_hash, tree_map_eq, free);
-         eh_offset = duplicate_eh_regions (saved_cfun, new_label_mapper,
-                                           new_label_map, region, 0);
+         eh_map = duplicate_eh_regions (saved_cfun, region, 0,
+                                        new_label_mapper, new_label_map);
        }
     }
 
@@ -6320,20 +6466,21 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
   vars_map = pointer_map_create ();
 
   memset (&d, 0, sizeof (d));
-  d.vars_map = vars_map;
+  d.orig_block = orig_block;
+  d.new_block = DECL_INITIAL (dest_cfun->decl);
   d.from_context = cfun->decl;
   d.to_context = dest_cfun->decl;
+  d.vars_map = vars_map;
   d.new_label_map = new_label_map;
+  d.eh_map = eh_map;
   d.remap_decls_p = true;
-  d.orig_block = orig_block;
-  d.new_block = DECL_INITIAL (dest_cfun->decl);
 
   for (i = 0; VEC_iterate (basic_block, bbs, i, bb); i++)
     {
       /* No need to update edge counts on the last block.  It has
         already been updated earlier when we detached the region from
         the original CFG.  */
-      move_block_to_fn (dest_cfun, bb, after, bb != exit_bb, &d, eh_offset);
+      move_block_to_fn (dest_cfun, bb, after, bb != exit_bb, &d);
       after = bb;
     }
 
@@ -6356,6 +6503,8 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
 
   if (new_label_map)
     htab_delete (new_label_map);
+  if (eh_map)
+    pointer_map_destroy (eh_map);
   pointer_map_destroy (vars_map);
 
   /* Rewire the entry and exit blocks.  The successor to the entry
index 5cce1b6eec7f58937865a763f813010521f6a12e..d3a8ca91aa993ab262be2b29298ed2d941a1e3da 100644 (file)
@@ -239,6 +239,16 @@ tree_forwarder_block_p (basic_block bb, bool phi_wanted)
   gcc_assert (bb != ENTRY_BLOCK_PTR);
 #endif
 
+  /* There should not be an edge coming from entry, or an EH edge.  */
+  {
+    edge_iterator ei;
+    edge e;
+
+    FOR_EACH_EDGE (e, ei, bb->preds)
+      if (e->src == ENTRY_BLOCK_PTR || (e->flags & EDGE_EH))
+       return false;
+  }
+
   /* Now walk through the statements backward.  We can ignore labels,
      anything else means this is not a forwarder block.  */
   for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi_prev (&gsi))
@@ -262,9 +272,6 @@ tree_forwarder_block_p (basic_block bb, bool phi_wanted)
        }
     }
 
-  if (find_edge (ENTRY_BLOCK_PTR, bb))
-    return false;
-
   if (current_loops)
     {
       basic_block dest;
index b6eff5ea8f16b8cd2764e00f7d25015f60f99762..e9a645ef7f237da1562586290103bb751a441585 100644 (file)
@@ -201,7 +201,6 @@ create_tree_common_ann (tree t)
   ann = GGC_CNEW (struct tree_ann_common_d);
 
   ann->type = TREE_ANN_COMMON;
-  ann->rn = -1;
   t->base.ann = (tree_ann_t) ann;
 
   return ann;
index ac87f424dcdc115e01b50aaa602b7507b018e712..a1aa4b21571a315ad480f2a3a2e842789b442aa6 100644 (file)
@@ -38,6 +38,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ggc.h"
 #include "toplev.h"
 #include "gimple.h"
+#include "target.h"
 
 /* In some instances a tree and a gimple need to be stored in a same table,
    i.e. in hash tables. This is a structure to do this. */
@@ -74,7 +75,7 @@ struct_ptr_hash (const void *a)
 }
 
 
-/* Remember and lookup EH region data for arbitrary statements.
+/* Remember and lookup EH landing pad data for arbitrary statements.
    Really this means any statement that could_throw_p.  We could
    stuff this information into the stmt_ann data structure, but:
 
@@ -86,30 +87,19 @@ struct_ptr_hash (const void *a)
    compared to those that can.  We should be saving some amount
    of space by only allocating memory for those that can throw.  */
 
-static void
-record_stmt_eh_region (struct eh_region_d *region, gimple t)
-{
-  if (!region)
-    return;
-
-  add_stmt_to_eh_region (t, get_eh_region_number (region));
-}
-
-
-/* Add statement T in function IFUN to EH region NUM.  */
+/* Add statement T in function IFUN to landing pad NUM.  */
 
 void
-add_stmt_to_eh_region_fn (struct function *ifun, gimple t, int num)
+add_stmt_to_eh_lp_fn (struct function *ifun, gimple t, int num)
 {
   struct throw_stmt_node *n;
   void **slot;
 
-  gcc_assert (num >= 0);
-  gcc_assert (gimple_code (t) != GIMPLE_RESX);
+  gcc_assert (num != 0);
 
   n = GGC_NEW (struct throw_stmt_node);
   n->stmt = t;
-  n->region_nr = num;
+  n->lp_nr = num;
 
   if (!get_eh_throw_stmt_table (ifun))
     set_eh_throw_stmt_table (ifun, htab_create_ggc (31, struct_ptr_hash,
@@ -121,21 +111,39 @@ add_stmt_to_eh_region_fn (struct function *ifun, gimple t, int num)
   *slot = n;
 }
 
-
-/* Add statement T in the current function (cfun) to EH region number
-   NUM.  */
+/* Add statement T in the current function (cfun) to EH landing pad NUM.  */
 
 void
-add_stmt_to_eh_region (gimple t, int num)
+add_stmt_to_eh_lp (gimple t, int num)
 {
-  add_stmt_to_eh_region_fn (cfun, t, num);
+  add_stmt_to_eh_lp_fn (cfun, t, num);
+}
+
+/* Add statement T to the single EH landing pad in REGION.  */
+
+static void
+record_stmt_eh_region (eh_region region, gimple t)
+{
+  if (region == NULL)
+    return;
+  if (region->type == ERT_MUST_NOT_THROW)
+    add_stmt_to_eh_lp_fn (cfun, t, -region->index);
+  else
+    {
+      eh_landing_pad lp = region->landing_pads;
+      if (lp == NULL)
+       lp = gen_eh_landing_pad (region);
+      else
+       gcc_assert (lp->next_lp == NULL);
+      add_stmt_to_eh_lp_fn (cfun, t, lp->index);
+    }
 }
 
 
-/* Remove statement T in function IFUN from the EH region holding it.  */
+/* Remove statement T in function IFUN from its EH landing pad.  */
 
 bool
-remove_stmt_from_eh_region_fn (struct function *ifun, gimple t)
+remove_stmt_from_eh_lp_fn (struct function *ifun, gimple t)
 {
   struct throw_stmt_node dummy;
   void **slot;
@@ -156,75 +164,57 @@ remove_stmt_from_eh_region_fn (struct function *ifun, gimple t)
 }
 
 
-/* Remove statement T in the current function (cfun) from the EH
-   region holding it.  */
+/* Remove statement T in the current function (cfun) from its
+   EH landing pad.  */
 
 bool
-remove_stmt_from_eh_region (gimple t)
+remove_stmt_from_eh_lp (gimple t)
 {
-  return remove_stmt_from_eh_region_fn (cfun, t);
+  return remove_stmt_from_eh_lp_fn (cfun, t);
 }
 
 /* Determine if statement T is inside an EH region in function IFUN.
-   Return the EH region number if found, return -2 if IFUN does not
-   have an EH table and -1 if T could not be found in IFUN's EH region
-   table.  */
+   Positive numbers indicate a landing pad index; negative numbers
+   indicate a MUST_NOT_THROW region index; zero indicates that the
+   statement is not recorded in the region table.  */
 
 int
-lookup_stmt_eh_region_fn (struct function *ifun, gimple t)
+lookup_stmt_eh_lp_fn (struct function *ifun, gimple t)
 {
   struct throw_stmt_node *p, n;
 
-  if (!get_eh_throw_stmt_table (ifun))
-    return -2;
+  if (ifun->eh->throw_stmt_table == NULL)
+    return 0;
 
   n.stmt = t;
-  p = (struct throw_stmt_node *) htab_find (get_eh_throw_stmt_table (ifun), &n);
-  return (p ? p->region_nr : -1);
+  p = (struct throw_stmt_node *) htab_find (ifun->eh->throw_stmt_table, &n);
+  return p ? p->lp_nr : 0;
 }
 
-
-/* Determine if statement T is inside an EH region in the current
-   function (cfun).  Return the EH region number if found, return -2
-   if cfun does not have an EH table and -1 if T could not be found in
-   cfun's EH region table.  */
+/* Likewise, but always use the current function.  */
 
 int
-lookup_stmt_eh_region (gimple t)
+lookup_stmt_eh_lp (gimple t)
 {
   /* We can get called from initialized data when -fnon-call-exceptions
      is on; prevent crash.  */
   if (!cfun)
-    return -1;
-
-  return lookup_stmt_eh_region_fn (cfun, t);
+    return 0;
+  return lookup_stmt_eh_lp_fn (cfun, t);
 }
 
-
-/* Determine if expression T is inside an EH region in the current
-   function (cfun).  Return the EH region number if found, return -2
-   if IFUN does not have an EH table and -1 if T could not be found in
-   IFUN's EH region table.  */
+/* Likewise, but reference a tree expression instead.  */
 
 int
-lookup_expr_eh_region (tree t)
+lookup_expr_eh_lp (tree t)
 {
-  /* We can get called from initialized data when -fnon-call-exceptions
-     is on; prevent crash.  */
-  if (!cfun)
-    return -1;
-
-  if (!get_eh_throw_stmt_table (cfun))
-    return -2;
-
-  if (t && EXPR_P (t))
+  if (cfun && cfun->eh->throw_stmt_table && t && EXPR_P (t))
     {
       tree_ann_common_t ann = tree_common_ann (t);
       if (ann)
-       return (int) ann->rn;
+       return ann->lp_nr;
     }
-
-  return -1;
+  return 0;
 }
 
 
@@ -238,7 +228,7 @@ struct finally_tree_node
      when deciding whether a GOTO to a certain LABEL_DECL (which is a
      tree) leaves the TRY block, its necessary to record a tree in
      this field.  Thus a treemple is used. */
-  treemple child; 
+  treemple child;
   gimple parent;
 };
 
@@ -263,7 +253,7 @@ record_in_finally_tree (treemple child, gimple parent)
 static void
 collect_finally_tree (gimple stmt, gimple region);
 
-/* Go through the gimple sequence.  Works with collect_finally_tree to 
+/* Go through the gimple sequence.  Works with collect_finally_tree to
    record all GIMPLE_LABEL and GIMPLE_TRY statements. */
 
 static void
@@ -344,6 +334,14 @@ outside_finally_tree (treemple start, gimple target)
    The eh region creation is straight-forward, but frobbing all the gotos
    and such into shape isn't.  */
 
+/* The sequence into which we record all EH stuff.  This will be 
+   placed at the end of the function when we're all done.  */
+static gimple_seq eh_seq;
+
+/* Record whether an EH region contains something that can throw,
+   indexed by EH region number.  */
+static bitmap eh_region_may_contain_throw;
+
 /* The GOTO_QUEUE is is an array of GIMPLE_GOTO and GIMPLE_RETURN
    statements that are seen to escape this GIMPLE_TRY_FINALLY node.
    The idea is to record a gimple statement for everything except for
@@ -371,7 +369,12 @@ struct leh_state
   /* What's "current" while constructing the eh region tree.  These
      correspond to variables of the same name in cfun->eh, which we
      don't have easy access to.  */
-  struct eh_region_d *cur_region;
+  eh_region cur_region;
+
+  /* What's "current" for the purposes of __builtin_eh_pointer.  For
+     a CATCH, this is the associated TRY.  For an EH_FILTER, this is
+     the associated ALLOWED_EXCEPTIONS, etc.  */
+  eh_region ehp_region;
 
   /* Processing of TRY_FINALLY requires a bit more state.  This is
      split out into a separate structure so that we don't have to
@@ -387,6 +390,7 @@ struct leh_tf_state
      in the collect_finally_tree data structures.  */
   gimple try_finally_expr;
   gimple top_p;
+
   /* While lowering a top_p usually it is expanded into multiple statements,
      thus we need the following field to store them. */
   gimple_seq top_p_seq;
@@ -395,7 +399,7 @@ struct leh_tf_state
   struct leh_state *outer;
 
   /* The exception region created for it.  */
-  struct eh_region_d *region;
+  eh_region region;
 
   /* The goto queue.  */
   struct goto_queue_node *goto_queue;
@@ -413,10 +417,6 @@ struct leh_tf_state
      though subsequent transformations may have cleared that flag.  */
   tree fallthru_label;
 
-  /* A label that has been registered with except.c to be the
-     landing pad for this try block.  */
-  tree eh_label;
-
   /* True if it is possible to fall out the bottom of the try block.
      Cleared if the fallthru is converted to a goto.  */
   bool may_fallthru;
@@ -429,7 +429,7 @@ struct leh_tf_state
   bool may_throw;
 };
 
-static gimple_seq lower_eh_filter (struct leh_state *, gimple);
+static gimple_seq lower_eh_must_not_throw (struct leh_state *, gimple);
 
 /* Search for STMT in the goto queue.  Return the replacement,
    or null if the statement isn't in the queue.  */
@@ -810,7 +810,7 @@ do_goto_redirection (struct goto_queue_node *q, tree finlab, gimple_seq mod,
   if (!q->repl_stmt)
     q->repl_stmt = gimple_seq_alloc ();
 
-  q->cont_stmt = gimple_build_goto (VEC_index (tree, tf->dest_array,q->index));
+  q->cont_stmt = gimple_build_goto (VEC_index (tree, tf->dest_array, q->index));
 
   if (mod)
     gimple_seq_add_seq (&q->repl_stmt, mod);
@@ -819,17 +819,76 @@ do_goto_redirection (struct goto_queue_node *q, tree finlab, gimple_seq mod,
   gimple_seq_add_stmt (&q->repl_stmt, x);
 }
 
+/* Emit a standard landing pad sequence into SEQ for REGION.  */
+
+static void
+emit_post_landing_pad (gimple_seq *seq, eh_region region)
+{
+  eh_landing_pad lp = region->landing_pads;
+  gimple x;
+
+  if (lp == NULL)
+    lp = gen_eh_landing_pad (region);
+
+  lp->post_landing_pad = create_artificial_label (UNKNOWN_LOCATION);
+  EH_LANDING_PAD_NR (lp->post_landing_pad) = lp->index;
+
+  x = gimple_build_label (lp->post_landing_pad);
+  gimple_seq_add_stmt (seq, x);
+}
+
+/* Emit a RESX statement into SEQ for REGION.  */
+
+static void
+emit_resx (gimple_seq *seq, eh_region region)
+{
+  gimple x = gimple_build_resx (region->index);
+  gimple_seq_add_stmt (seq, x);
+  if (region->outer)
+    record_stmt_eh_region (region->outer, x);
+}
+
+/* Emit an EH_DISPATCH statement into SEQ for REGION.  */
+
+static void
+emit_eh_dispatch (gimple_seq *seq, eh_region region)
+{
+  gimple x = gimple_build_eh_dispatch (region->index);
+  gimple_seq_add_stmt (seq, x);
+}
+
+/* Note that the current EH region may contain a throw, or a
+   call to a function which itself may contain a throw.  */
+
+static void
+note_eh_region_may_contain_throw (eh_region region)
+{
+  while (!bitmap_bit_p (eh_region_may_contain_throw, region->index))
+    {
+      bitmap_set_bit (eh_region_may_contain_throw, region->index);
+      region = region->outer;
+      if (region == NULL)
+       break;
+    }
+}
+
 /* We want to transform
        try { body; } catch { stuff; }
    to
-       body; goto over; lab: stuff; over:
-
-   TP is a GIMPLE_TRY node.  LAB is the label that
+       normal_seqence:
+         body;
+         over:
+       eh_seqence:
+         landing_pad:
+         stuff;
+         goto over;
+
+   TP is a GIMPLE_TRY node.  REGION is the region whose post_landing_pad
    should be placed before the second operand, or NULL.  OVER is
    an existing label that should be put at the exit, or NULL.  */
 
 static gimple_seq
-frob_into_branch_around (gimple tp, tree lab, tree over)
+frob_into_branch_around (gimple tp, eh_region region, tree over)
 {
   gimple x;
   gimple_seq cleanup, result;
@@ -838,21 +897,17 @@ frob_into_branch_around (gimple tp, tree lab, tree over)
   cleanup = gimple_try_cleanup (tp);
   result = gimple_try_eval (tp);
 
-  if (gimple_seq_may_fallthru (result))
+  if (region)
+    emit_post_landing_pad (&eh_seq, region);
+
+  if (gimple_seq_may_fallthru (cleanup))
     {
       if (!over)
        over = create_artificial_label (loc);
       x = gimple_build_goto (over);
-      gimple_seq_add_stmt (&result, x);
-    }
-
-  if (lab)
-    {
-      x = gimple_build_label (lab);
-      gimple_seq_add_stmt (&result, x);
+      gimple_seq_add_stmt (&cleanup, x);
     }
-
-  gimple_seq_add_seq (&result, cleanup);
+  gimple_seq_add_seq (&eh_seq, cleanup);
 
   if (over)
     {
@@ -928,44 +983,21 @@ honor_protect_cleanup_actions (struct leh_state *outer_state,
                               struct leh_state *this_state,
                               struct leh_tf_state *tf)
 {
-  gimple protect_cleanup_actions;
+  tree protect_cleanup_actions;
   gimple_stmt_iterator gsi;
   bool finally_may_fallthru;
   gimple_seq finally;
   gimple x;
 
   /* First check for nothing to do.  */
-  if (lang_protect_cleanup_actions)
-    protect_cleanup_actions = lang_protect_cleanup_actions ();
-  else
-    protect_cleanup_actions = NULL;
+  if (lang_protect_cleanup_actions == NULL)
+    return;
+  protect_cleanup_actions = lang_protect_cleanup_actions ();
+  if (protect_cleanup_actions == NULL)
+    return;
 
   finally = gimple_try_cleanup (tf->top_p);
-
-  /* If the EH case of the finally block can fall through, this may be a
-     structure of the form
-       try {
-         try {
-           throw ...;
-         } cleanup {
-           try {
-             throw ...;
-           } catch (...) {
-           }
-         }
-       } catch (...) {
-         yyy;
-       }
-    E.g. with an inline destructor with an embedded try block.  In this
-    case we must save the runtime EH data around the nested exception.
-
-    This complication means that any time the previous runtime data might
-    be used (via fallthru from the finally) we handle the eh case here,
-    whether or not protect_cleanup_actions is active.  */
-
   finally_may_fallthru = gimple_seq_may_fallthru (finally);
-  if (!finally_may_fallthru && !protect_cleanup_actions)
-    return;
 
   /* Duplicate the FINALLY block.  Only need to do this for try-finally,
      and not for cleanups.  */
@@ -981,8 +1013,7 @@ honor_protect_cleanup_actions (struct leh_state *outer_state,
      MUST_NOT_THROW filter.  */
   gsi = gsi_start (finally);
   x = gsi_stmt (gsi);
-  if (protect_cleanup_actions
-      && gimple_code (x) == GIMPLE_TRY
+  if (gimple_code (x) == GIMPLE_TRY
       && gimple_try_kind (x) == GIMPLE_TRY_CATCH
       && gimple_try_catch_is_cleanup (x))
     {
@@ -990,77 +1021,17 @@ honor_protect_cleanup_actions (struct leh_state *outer_state,
       gsi_remove (&gsi, false);
     }
 
-  /* Resume execution after the exception.  Adding this now lets
-     lower_eh_filter not add unnecessary gotos, as it is clear that
-     we never fallthru from this copy of the finally block.  */
-  if (finally_may_fallthru)
-    {
-      tree save_eptr, save_filt;
-      tree tmp;
-
-      save_eptr = create_tmp_var (ptr_type_node, "save_eptr");
-      save_filt = create_tmp_var (integer_type_node, "save_filt");
-
-      gsi = gsi_start (finally);
-      tmp = build0 (EXC_PTR_EXPR, ptr_type_node);
-      x = gimple_build_assign (save_eptr, tmp);
-      gsi_insert_before (&gsi, x, GSI_CONTINUE_LINKING);
-
-      tmp = build0 (FILTER_EXPR, integer_type_node);
-      x = gimple_build_assign (save_filt, tmp);
-      gsi_insert_before (&gsi, x, GSI_CONTINUE_LINKING);
-
-      gsi = gsi_last (finally);
-      tmp = build0 (EXC_PTR_EXPR, ptr_type_node);
-      x = gimple_build_assign (tmp, save_eptr);
-      gsi_insert_after (&gsi, x, GSI_CONTINUE_LINKING);
-
-      tmp = build0 (FILTER_EXPR, integer_type_node);
-      x = gimple_build_assign (tmp, save_filt);
-      gsi_insert_after (&gsi, x, GSI_CONTINUE_LINKING);
-
-      x = gimple_build_resx (get_eh_region_number (tf->region));
-      gsi_insert_after (&gsi, x, GSI_CONTINUE_LINKING);
-    }
-
   /* Wrap the block with protect_cleanup_actions as the action.  */
-  if (protect_cleanup_actions)
-    {
-      gimple_seq seq = NULL, failure = NULL;
-
-      gimple_seq_add_stmt (&failure, protect_cleanup_actions);
-      x = gimple_build_eh_filter (NULL, failure);
-      gimple_eh_filter_set_must_not_throw (x, 1);
-
-      gimple_seq_add_stmt (&seq, x);
-      x = gimple_build_try (finally, seq, GIMPLE_TRY_CATCH);
-      finally = lower_eh_filter (outer_state, x);
-    }
-  else
-    lower_eh_constructs_1 (outer_state, finally);
-
-  /* Hook this up to the end of the existing try block.  If we
-     previously fell through the end, we'll have to branch around.
-     This means adding a new goto, and adding it to the queue.  */
-
-  gsi = gsi_last (gimple_try_eval (tf->top_p));
-
-  if (tf->may_fallthru)
-    {
-      tree tmp;
-      tmp = lower_try_finally_fallthru_label (tf);
-      x = gimple_build_goto (tmp);
-      gsi_insert_after (&gsi, x, GSI_CONTINUE_LINKING);
-
-      if (this_state)
-        maybe_record_in_goto_queue (this_state, x);
-
-      tf->may_fallthru = false;
-    }
-
-  x = gimple_build_label (tf->eh_label);
-  gsi_insert_after (&gsi, x, GSI_CONTINUE_LINKING);
-  gsi_insert_seq_after (&gsi, finally, GSI_CONTINUE_LINKING);
+  x = gimple_build_eh_must_not_throw (protect_cleanup_actions);
+  x = gimple_build_try (finally, gimple_seq_alloc_with_stmt (x),
+                       GIMPLE_TRY_CATCH);
+  finally = lower_eh_must_not_throw (outer_state, x);
+
+  /* Drop all of this into the exception sequence.  */
+  emit_post_landing_pad (&eh_seq, tf->region);
+  gimple_seq_add_seq (&eh_seq, finally);
+  if (finally_may_fallthru)
+    emit_resx (&eh_seq, tf->region);
 
   /* Having now been handled, EH isn't to be considered with
      the rest of the outgoing edges.  */
@@ -1081,10 +1052,7 @@ lower_try_finally_nofallthru (struct leh_state *state,
   gimple_seq finally;
   struct goto_queue_node *q, *qe;
 
-  if (tf->may_throw)
-    lab = tf->eh_label;
-  else
-    lab = create_artificial_label (gimple_location (tf->try_finally_expr));
+  lab = create_artificial_label (gimple_location (tf->try_finally_expr));
 
   /* We expect that tf->top_p is a GIMPLE_TRY. */
   finally = gimple_try_cleanup (tf->top_p);
@@ -1106,6 +1074,14 @@ lower_try_finally_nofallthru (struct leh_state *state,
 
   lower_eh_constructs_1 (state, finally);
   gimple_seq_add_seq (&tf->top_p_seq, finally);
+
+  if (tf->may_throw)
+    {
+      emit_post_landing_pad (&eh_seq, tf->region);
+
+      x = gimple_build_goto (lab);
+      gimple_seq_add_stmt (&eh_seq, x);
+    }
 }
 
 /* A subroutine of lower_try_finally.  We have determined that there is
@@ -1130,16 +1106,9 @@ lower_try_finally_onedest (struct leh_state *state, struct leh_tf_state *tf)
     {
       /* Only reachable via the exception edge.  Add the given label to
          the head of the FINALLY block.  Append a RESX at the end.  */
-
-      x = gimple_build_label (tf->eh_label);
-      gimple_seq_add_stmt (&tf->top_p_seq, x);
-
-      gimple_seq_add_seq (&tf->top_p_seq, finally);
-
-      x = gimple_build_resx (get_eh_region_number (tf->region));
-
-      gimple_seq_add_stmt (&tf->top_p_seq, x);
-
+      emit_post_landing_pad (&eh_seq, tf->region);
+      gimple_seq_add_seq (&eh_seq, finally);
+      emit_resx (&eh_seq, tf->region);
       return;
     }
 
@@ -1223,15 +1192,13 @@ lower_try_finally_copy (struct leh_state *state, struct leh_tf_state *tf)
 
   if (tf->may_throw)
     {
-      x = gimple_build_label (tf->eh_label);
-      gimple_seq_add_stmt (&new_stmt, x);
+      emit_post_landing_pad (&eh_seq, tf->region);
 
       seq = lower_try_finally_dup_block (finally, state);
       lower_eh_constructs_1 (state, seq);
-      gimple_seq_add_seq (&new_stmt, seq);
+      gimple_seq_add_seq (&eh_seq, seq);
 
-      x = gimple_build_resx (get_eh_region_number (tf->region));
-      gimple_seq_add_stmt (&new_stmt, x);
+      emit_resx (&eh_seq, tf->region);
     }
 
   if (tf->goto_queue)
@@ -1301,7 +1268,7 @@ lower_try_finally_copy (struct leh_state *state, struct leh_tf_state *tf)
          else
            do_goto_redirection (q, lab, NULL, tf);
        }
-       
+
       replace_goto_queue (tf);
       free (labels);
     }
@@ -1375,20 +1342,13 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
 
   if (tf->may_fallthru)
     {
-      x = gimple_build_assign (finally_tmp, build_int_cst (integer_type_node,
-                                                          fallthru_index));
+      x = gimple_build_assign (finally_tmp,
+                              build_int_cst (NULL, fallthru_index));
       gimple_seq_add_stmt (&tf->top_p_seq, x);
 
-      if (tf->may_throw)
-       {
-         x = gimple_build_goto (finally_label);
-          gimple_seq_add_stmt (&tf->top_p_seq, x);
-       }
-
-
       last_case = build3 (CASE_LABEL_EXPR, void_type_node,
-                         build_int_cst (NULL_TREE, fallthru_index), NULL,
-                         create_artificial_label (tf_loc));
+                         build_int_cst (NULL, fallthru_index),
+                         NULL, create_artificial_label (tf_loc));
       VEC_quick_push (tree, case_label_vec, last_case);
       last_case_index++;
 
@@ -1402,23 +1362,24 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
 
   if (tf->may_throw)
     {
-      x = gimple_build_label (tf->eh_label);
-      gimple_seq_add_stmt (&tf->top_p_seq, x);
+      emit_post_landing_pad (&eh_seq, tf->region);
 
-      x = gimple_build_assign (finally_tmp, build_int_cst (integer_type_node,
-                                                           eh_index));
-      gimple_seq_add_stmt (&tf->top_p_seq, x);
+      x = gimple_build_assign (finally_tmp,
+                              build_int_cst (NULL, eh_index));
+      gimple_seq_add_stmt (&eh_seq, x);
+
+      x = gimple_build_goto (finally_label);
+      gimple_seq_add_stmt (&eh_seq, x);
 
       last_case = build3 (CASE_LABEL_EXPR, void_type_node,
-                         build_int_cst (NULL_TREE, eh_index), NULL,
-                         create_artificial_label (tf_loc));
+                         build_int_cst (NULL, eh_index),
+                         NULL, create_artificial_label (tf_loc));
       VEC_quick_push (tree, case_label_vec, last_case);
       last_case_index++;
 
       x = gimple_build_label (CASE_LABEL (last_case));
-      gimple_seq_add_stmt (&switch_body, x);
-      x = gimple_build_resx (get_eh_region_number (tf->region));
-      gimple_seq_add_stmt (&switch_body, x);
+      gimple_seq_add_stmt (&eh_seq, x);
+      emit_resx (&eh_seq, tf->region);
     }
 
   x = gimple_build_label (finally_label);
@@ -1443,8 +1404,7 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
       if (q->index < 0)
        {
          x = gimple_build_assign (finally_tmp,
-                                  build_int_cst (integer_type_node,
-                                                 return_index));
+                                  build_int_cst (NULL, return_index));
          gimple_seq_add_stmt (&mod, x);
          do_return_redirection (q, finally_label, mod, &return_val);
          switch_id = return_index;
@@ -1452,7 +1412,7 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
       else
        {
          x = gimple_build_assign (finally_tmp,
-                                  build_int_cst (integer_type_node, q->index));
+                                  build_int_cst (NULL, q->index));
          gimple_seq_add_stmt (&mod, x);
          do_goto_redirection (q, finally_label, mod, tf);
          switch_id = q->index;
@@ -1465,11 +1425,11 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
           tree case_lab;
           void **slot;
           case_lab = build3 (CASE_LABEL_EXPR, void_type_node,
-                             build_int_cst (NULL_TREE, switch_id), NULL,
-                             NULL);
+                             build_int_cst (NULL, switch_id),
+                            NULL, NULL);
           /* We store the cont_stmt in the pointer map, so that we can recover
              it in the loop below.  We don't create the new label while
-             walking the goto_queue because pointers don't offer a stable 
+             walking the goto_queue because pointers don't offer a stable
              order.  */
           if (!cont_map)
             cont_map = pointer_map_create ();
@@ -1577,7 +1537,6 @@ lower_try_finally (struct leh_state *state, gimple tp)
   struct leh_tf_state this_tf;
   struct leh_state this_state;
   int ndests;
-  location_t tf_loc = gimple_location (tp);
 
   /* Process the try block.  */
 
@@ -1586,12 +1545,12 @@ lower_try_finally (struct leh_state *state, gimple tp)
   this_tf.top_p = tp;
   this_tf.outer = state;
   if (using_eh_for_cleanups_p)
-    this_tf.region
-      = gen_eh_region_cleanup (state->cur_region);
+    this_tf.region = gen_eh_region_cleanup (state->cur_region);
   else
     this_tf.region = NULL;
 
   this_state.cur_region = this_tf.region;
+  this_state.ehp_region = state->ehp_region;
   this_state.tf = &this_tf;
 
   lower_eh_constructs_1 (&this_state, gimple_try_eval(tp));
@@ -1601,13 +1560,10 @@ lower_try_finally (struct leh_state *state, gimple tp)
 
   /* Determine if any exceptions are possible within the try block.  */
   if (using_eh_for_cleanups_p)
-    this_tf.may_throw = get_eh_region_may_contain_throw (this_tf.region);
+    this_tf.may_throw = bitmap_bit_p (eh_region_may_contain_throw,
+                                     this_tf.region->index);
   if (this_tf.may_throw)
-    {
-      this_tf.eh_label = create_artificial_label (tf_loc);
-      set_eh_region_tree_label (this_tf.region, this_tf.eh_label);
-      honor_protect_cleanup_actions (state, &this_state, &this_tf);
-    }
+    honor_protect_cleanup_actions (state, &this_state, &this_tf);
 
   /* Determine how many edges (still) reach the finally block.  Or rather,
      how many destinations are reached by the finally block.  Use this to
@@ -1663,58 +1619,65 @@ lower_try_finally (struct leh_state *state, gimple tp)
 static gimple_seq
 lower_catch (struct leh_state *state, gimple tp)
 {
-  struct eh_region_d *try_region;
+  eh_region try_region;
   struct leh_state this_state;
   gimple_stmt_iterator gsi;
   tree out_label;
+  gimple_seq new_seq;
+  gimple x;
   location_t try_catch_loc = gimple_location (tp);
 
   try_region = gen_eh_region_try (state->cur_region);
+
+  this_state = *state;
   this_state.cur_region = try_region;
-  this_state.tf = state->tf;
 
   lower_eh_constructs_1 (&this_state, gimple_try_eval (tp));
 
-  if (!get_eh_region_may_contain_throw (try_region))
-    {
-      return gimple_try_eval (tp);
-    }
+  if (!bitmap_bit_p (eh_region_may_contain_throw, try_region->index))
+    return gimple_try_eval (tp);
+
+  new_seq = NULL;
+  emit_eh_dispatch (&new_seq, try_region);
+  emit_resx (&new_seq, try_region);
+
+  this_state.cur_region = state->cur_region;
+  this_state.ehp_region = try_region;
 
   out_label = NULL;
-  for (gsi = gsi_start (gimple_try_cleanup (tp)); !gsi_end_p (gsi); )
+  for (gsi = gsi_start (gimple_try_cleanup (tp));
+       !gsi_end_p (gsi);
+       gsi_next (&gsi))
     {
-      struct eh_region_d *catch_region;
-      tree eh_label;
-      gimple x, gcatch;
+      eh_catch c;
+      gimple gcatch;
+      gimple_seq handler;
 
       gcatch = gsi_stmt (gsi);
-      catch_region = gen_eh_region_catch (try_region,
-                                          gimple_catch_types (gcatch));
+      c = gen_eh_region_catch (try_region, gimple_catch_types (gcatch));
 
-      this_state.cur_region = catch_region;
-      lower_eh_constructs_1 (&this_state, gimple_catch_handler (gcatch));
+      handler = gimple_catch_handler (gcatch);
+      lower_eh_constructs_1 (&this_state, handler);
 
-      eh_label = create_artificial_label (try_catch_loc);
-      set_eh_region_tree_label (catch_region, eh_label);
+      c->label = create_artificial_label (UNKNOWN_LOCATION);
+      x = gimple_build_label (c->label);
+      gimple_seq_add_stmt (&new_seq, x);
 
-      x = gimple_build_label (eh_label);
-      gsi_insert_before (&gsi, x, GSI_SAME_STMT);
+      gimple_seq_add_seq (&new_seq, handler);
 
-      if (gimple_seq_may_fallthru (gimple_catch_handler (gcatch)))
+      if (gimple_seq_may_fallthru (new_seq))
        {
          if (!out_label)
            out_label = create_artificial_label (try_catch_loc);
 
          x = gimple_build_goto (out_label);
-         gimple_seq_add_stmt (gimple_catch_handler_ptr (gcatch), x);
+         gimple_seq_add_stmt (&new_seq, x);
        }
-
-      gsi_insert_seq_before (&gsi, gimple_catch_handler (gcatch),
-                            GSI_SAME_STMT);
-      gsi_remove (&gsi, false);
     }
 
-  return frob_into_branch_around (tp, NULL, out_label);
+  gimple_try_set_cleanup (tp, new_seq);
+
+  return frob_into_branch_around (tp, try_region, out_label);
 }
 
 /* A subroutine of lower_eh_constructs_1.  Lower a GIMPLE_TRY with a
@@ -1725,34 +1688,70 @@ static gimple_seq
 lower_eh_filter (struct leh_state *state, gimple tp)
 {
   struct leh_state this_state;
-  struct eh_region_d *this_region;
-  gimple inner;
-  tree eh_label;
+  eh_region this_region;
+  gimple inner, x;
+  gimple_seq new_seq;
 
   inner = gimple_seq_first_stmt (gimple_try_cleanup (tp));
 
-  if (gimple_eh_filter_must_not_throw (inner))
-    this_region = gen_eh_region_must_not_throw (state->cur_region);
-  else
-    this_region = gen_eh_region_allowed (state->cur_region,
-                                        gimple_eh_filter_types (inner));
+  this_region = gen_eh_region_allowed (state->cur_region,
+                                      gimple_eh_filter_types (inner));
   this_state = *state;
   this_state.cur_region = this_region;
 
   lower_eh_constructs_1 (&this_state, gimple_try_eval (tp));
 
-  if (!get_eh_region_may_contain_throw (this_region))
-    {
-      return gimple_try_eval (tp);
-    }
+  if (!bitmap_bit_p (eh_region_may_contain_throw, this_region->index))
+    return gimple_try_eval (tp);
+
+  new_seq = NULL;
+  this_state.cur_region = state->cur_region;
+  this_state.ehp_region = this_region;
+
+  emit_eh_dispatch (&new_seq, this_region);
+  emit_resx (&new_seq, this_region);
+
+  this_region->u.allowed.label = create_artificial_label (UNKNOWN_LOCATION);
+  x = gimple_build_label (this_region->u.allowed.label);
+  gimple_seq_add_stmt (&new_seq, x);
+
+  lower_eh_constructs_1 (&this_state, gimple_eh_filter_failure (inner));
+  gimple_seq_add_seq (&new_seq, gimple_eh_filter_failure (inner));
+
+  gimple_try_set_cleanup (tp, new_seq);
 
-  lower_eh_constructs_1 (state, gimple_eh_filter_failure (inner));
-  gimple_try_set_cleanup (tp, gimple_eh_filter_failure (inner));
+  return frob_into_branch_around (tp, this_region, NULL);
+}
+
+/* A subroutine of lower_eh_constructs_1.  Lower a GIMPLE_TRY with
+   an GIMPLE_EH_MUST_NOT_THROW to a sequence of labels and blocks,
+   plus the exception region trees that record all the magic.  */
+
+static gimple_seq
+lower_eh_must_not_throw (struct leh_state *state, gimple tp)
+{
+  struct leh_state this_state;
+  eh_region this_region;
+  gimple inner;
+
+  inner = gimple_seq_first_stmt (gimple_try_cleanup (tp));
+
+  this_region = gen_eh_region_must_not_throw (state->cur_region);
+  this_region->u.must_not_throw.failure_decl
+    = gimple_eh_must_not_throw_fndecl (inner);
+  this_region->u.must_not_throw.failure_loc = gimple_location (tp);
+
+  /* In order to get mangling applied to this decl, we must mark it
+     used now.  Otherwise, pass_ipa_free_lang_data won't think it
+     needs to happen.  */
+  TREE_USED (this_region->u.must_not_throw.failure_decl) = 1;
+
+  this_state = *state;
+  this_state.cur_region = this_region;
 
-  eh_label = create_artificial_label (gimple_location (inner));
-  set_eh_region_tree_label (this_region, eh_label);
+  lower_eh_constructs_1 (&this_state, gimple_try_eval (tp));
 
-  return frob_into_branch_around (tp, eh_label, NULL);
+  return gimple_try_eval (tp);
 }
 
 /* Implement a cleanup expression.  This is similar to try-finally,
@@ -1762,7 +1761,7 @@ static gimple_seq
 lower_cleanup (struct leh_state *state, gimple tp)
 {
   struct leh_state this_state;
-  struct eh_region_d *this_region;
+  eh_region this_region;
   struct leh_tf_state fake_tf;
   gimple_seq result;
 
@@ -1780,10 +1779,8 @@ lower_cleanup (struct leh_state *state, gimple tp)
 
   lower_eh_constructs_1 (&this_state, gimple_try_eval (tp));
 
-  if (!get_eh_region_may_contain_throw (this_region))
-    {
-      return gimple_try_eval (tp);
-    }
+  if (!bitmap_bit_p (eh_region_may_contain_throw, this_region->index))
+    return gimple_try_eval (tp);
 
   /* Build enough of a try-finally state so that we can reuse
      honor_protect_cleanup_actions.  */
@@ -1794,9 +1791,6 @@ lower_cleanup (struct leh_state *state, gimple tp)
   fake_tf.may_fallthru = gimple_seq_may_fallthru (gimple_try_eval (tp));
   fake_tf.may_throw = true;
 
-  fake_tf.eh_label = create_artificial_label (gimple_location (tp));
-  set_eh_region_tree_label (this_region, fake_tf.eh_label);
-
   honor_protect_cleanup_actions (state, NULL, &fake_tf);
 
   if (fake_tf.may_throw)
@@ -1804,8 +1798,8 @@ lower_cleanup (struct leh_state *state, gimple tp)
       /* In this case honor_protect_cleanup_actions had nothing to do,
         and we should process this normally.  */
       lower_eh_constructs_1 (state, gimple_try_cleanup (tp));
-      result = frob_into_branch_around (tp, fake_tf.eh_label,
-                                       fake_tf.fallthru_label);
+      result = frob_into_branch_around (tp, this_region,
+                                        fake_tf.fallthru_label);
     }
   else
     {
@@ -1822,9 +1816,7 @@ lower_cleanup (struct leh_state *state, gimple tp)
   return result;
 }
 
-
-
-/* Main loop for lowering eh constructs. Also moves gsi to the next 
+/* Main loop for lowering eh constructs. Also moves gsi to the next
    statement. */
 
 static void
@@ -1837,6 +1829,52 @@ lower_eh_constructs_2 (struct leh_state *state, gimple_stmt_iterator *gsi)
   switch (gimple_code (stmt))
     {
     case GIMPLE_CALL:
+      {
+       tree fndecl = gimple_call_fndecl (stmt);
+       tree rhs, lhs;
+
+       if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
+         switch (DECL_FUNCTION_CODE (fndecl))
+           {
+           case BUILT_IN_EH_POINTER:
+             /* The front end may have generated a call to
+                __builtin_eh_pointer (0) within a catch region.  Replace
+                this zero argument with the current catch region number.  */
+             if (state->ehp_region)
+               {
+                 tree nr = build_int_cst (NULL, state->ehp_region->index);
+                 gimple_call_set_arg (stmt, 0, nr);
+               }
+             else
+               {
+                 /* The user has dome something silly.  Remove it.  */
+                 rhs = build_int_cst (ptr_type_node, 0);
+                 goto do_replace;
+               }
+             break;
+
+           case BUILT_IN_EH_FILTER:
+             /* ??? This should never appear, but since it's a builtin it
+                is accessible to abuse by users.  Just remove it and
+                replace the use with the arbitrary value zero.  */
+             rhs = build_int_cst (TREE_TYPE (TREE_TYPE (fndecl)), 0);
+           do_replace:
+             lhs = gimple_call_lhs (stmt);
+             x = gimple_build_assign (lhs, rhs);
+             gsi_insert_before (gsi, x, GSI_SAME_STMT);
+             /* FALLTHRU */
+
+           case BUILT_IN_EH_COPY_VALUES:
+             /* Likewise this should not appear.  Remove it.  */
+             gsi_remove (gsi, true);
+             return;
+
+           default:
+             break;
+           }
+      }
+      /* FALLTHRU */
+
     case GIMPLE_ASSIGN:
       /* If the stmt can throw use a new temporary for the assignment
          to a LHS.  This makes sure the old value of the LHS is
@@ -1889,6 +1927,9 @@ lower_eh_constructs_2 (struct leh_state *state, gimple_stmt_iterator *gsi)
            case GIMPLE_EH_FILTER:
              replace = lower_eh_filter (state, stmt);
              break;
+           case GIMPLE_EH_MUST_NOT_THROW:
+             replace = lower_eh_must_not_throw (state, stmt);
+             break;
            default:
              replace = lower_cleanup (state, stmt);
              break;
@@ -1926,19 +1967,32 @@ static unsigned int
 lower_eh_constructs (void)
 {
   struct leh_state null_state;
+  gimple_seq bodyp;
 
-  gimple_seq bodyp = gimple_body (current_function_decl);
+  bodyp = gimple_body (current_function_decl);
+  if (bodyp == NULL)
+    return 0;
 
   finally_tree = htab_create (31, struct_ptr_hash, struct_ptr_eq, free);
+  eh_region_may_contain_throw = BITMAP_ALLOC (NULL);
+  memset (&null_state, 0, sizeof (null_state));
 
   collect_finally_tree_1 (bodyp, NULL);
-
-  memset (&null_state, 0, sizeof (null_state));
   lower_eh_constructs_1 (&null_state, bodyp);
 
-  htab_delete (finally_tree);
+  /* We assume there's a return statement, or something, at the end of
+     the function, and thus ploping the EH sequence afterward won't
+     change anything.  */
+  gcc_assert (!gimple_seq_may_fallthru (bodyp));
+  gimple_seq_add_seq (&bodyp, eh_seq);
+
+  /* We assume that since BODYP already existed, adding EH_SEQ to it
+     didn't change its value, and we don't have to re-set the function.  */
+  gcc_assert (bodyp == gimple_body (current_function_decl));
 
-  collect_eh_region_array ();
+  htab_delete (finally_tree);
+  BITMAP_FREE (eh_region_may_contain_throw);
+  eh_seq = NULL;
 
   /* If this function needs a language specific EH personality routine
      and the frontend didn't already set one do so now.  */
@@ -1968,222 +2022,206 @@ struct gimple_opt_pass pass_lower_eh =
   TODO_dump_func                       /* todo_flags_finish */
  }
 };
-
 \f
-/* Construct EH edges for STMT.  */
+/* Create the multiple edges from an EH_DISPATCH statement to all of
+   the possible handlers for its EH region.  Return true if there's
+   no fallthru edge; false if there is.  */
 
-static void
-make_eh_edge (struct eh_region_d *region, void *data)
+bool
+make_eh_dispatch_edges (gimple stmt)
 {
-  gimple stmt;
-  tree lab;
+  eh_region r;
+  eh_catch c;
   basic_block src, dst;
 
-  stmt = (gimple) data;
-  lab = get_eh_region_tree_label (region);
-
+  r = get_eh_region_from_number (gimple_eh_dispatch_region (stmt));
   src = gimple_bb (stmt);
-  dst = label_to_block (lab);
 
-  make_edge (src, dst, EDGE_EH);
-}
+  switch (r->type)
+    {
+    case ERT_TRY:
+      for (c = r->u.eh_try.first_catch; c ; c = c->next_catch)
+       {
+         dst = label_to_block (c->label);
+         make_edge (src, dst, 0);
 
-/* See if STMT is call that might be inlined.  */
+         /* A catch-all handler doesn't have a fallthru.  */
+         if (c->type_list == NULL)
+           return false;
+       }
+      break;
 
-static bool
-inlinable_call_p (gimple stmt)
-{
-  tree decl;
-  if (gimple_code (stmt) != GIMPLE_CALL)
-    return false;
-  if (cfun->after_inlining)
-    return false;
-  /* Indirect calls can be propagated to direct call
-     and inlined.  */
-  decl = gimple_call_fndecl (stmt);
-  if (!decl)
-    return true;
-  if (cgraph_function_flags_ready
-      && cgraph_function_body_availability (cgraph_node (decl))
-      < AVAIL_OVERWRITABLE)
-    return false;
-  return !DECL_UNINLINABLE (decl);
+    case ERT_ALLOWED_EXCEPTIONS:
+      dst = label_to_block (r->u.allowed.label);
+      make_edge (src, dst, 0);
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  return true;
 }
 
+/* Create the single EH edge from STMT to its nearest landing pad,
+   if there is such a landing pad within the current function.  */
+
 void
 make_eh_edges (gimple stmt)
 {
-  int region_nr;
-  bool is_resx;
-  bool inlinable = false;
-  basic_block bb;
+  basic_block src, dst;
+  eh_landing_pad lp;
+  int lp_nr;
 
-  if (gimple_code (stmt) == GIMPLE_RESX)
-    {
-      region_nr = gimple_resx_region (stmt);
-      is_resx = true;
-    }
-  else
-    {
-      region_nr = lookup_stmt_eh_region (stmt);
-      if (region_nr < 0)
-       return;
-      is_resx = false;
-      inlinable = inlinable_call_p (stmt);
-    }
+  lp_nr = lookup_stmt_eh_lp (stmt);
+  if (lp_nr <= 0)
+    return;
 
-  foreach_reachable_handler (region_nr, is_resx, inlinable, make_eh_edge, stmt);
+  lp = get_eh_landing_pad_from_number (lp_nr);
+  gcc_assert (lp != NULL);
 
-  /* Make CFG profile more consistent assuming that exception will resume to first
-     available EH handler.  In practice this makes little difference, but we get
-     fewer consistency errors in the dumps.  */
-  bb = gimple_bb (stmt);
-  if (is_resx && EDGE_COUNT (bb->succs))
-    EDGE_SUCC (bb, 0)->probability = REG_BR_PROB_BASE;
+  src = gimple_bb (stmt);
+  dst = label_to_block (lp->post_landing_pad);
+  make_edge (src, dst, EDGE_EH);
 }
 
-/* Redirect EH edge E to NEW_BB.  */
+/* Do the work in redirecting EDGE_IN to NEW_BB within the EH region tree;
+   do not actually perform the final edge redirection.
 
-edge
-redirect_eh_edge (edge e, basic_block new_bb)
+   CHANGE_REGION is true when we're being called from cleanup_empty_eh and
+   we intend to change the destination EH region as well; this means
+   EH_LANDING_PAD_NR must already be set on the destination block label.
+   If false, we're being called from generic cfg manipulation code and we
+   should preserve our place within the region tree.  */
+
+static void
+redirect_eh_edge_1 (edge edge_in, basic_block new_bb, bool change_region)
 {
-  gimple stmt = gsi_stmt (gsi_last_bb (e->src));
-  int region_nr, new_region_nr;
-  bool is_resx;
-  bool inlinable = false;
-  tree label = gimple_block_label (new_bb);
-  struct eh_region_d *r;
+  eh_landing_pad old_lp, new_lp;
+  basic_block old_bb;
+  gimple throw_stmt;
+  int old_lp_nr, new_lp_nr;
+  tree old_label, new_label;
+  edge_iterator ei;
+  edge e;
+
+  old_bb = edge_in->dest;
+  old_label = gimple_block_label (old_bb);
+  old_lp_nr = EH_LANDING_PAD_NR (old_label);
+  gcc_assert (old_lp_nr > 0);
+  old_lp = get_eh_landing_pad_from_number (old_lp_nr);
+
+  throw_stmt = last_stmt (edge_in->src);
+  gcc_assert (lookup_stmt_eh_lp (throw_stmt) == old_lp_nr);
+
+  new_label = gimple_block_label (new_bb);
 
-  if (gimple_code (stmt) == GIMPLE_RESX)
+  /* Look for an existing region that might be using NEW_BB already.  */
+  new_lp_nr = EH_LANDING_PAD_NR (new_label);
+  if (new_lp_nr)
     {
-      region_nr = gimple_resx_region (stmt);
-      is_resx = true;
+      new_lp = get_eh_landing_pad_from_number (new_lp_nr);
+      gcc_assert (new_lp);
+      
+      /* Unless CHANGE_REGION is true, the new and old landing pad
+        had better be associated with the same EH region.  */
+      gcc_assert (change_region || new_lp->region == old_lp->region);
     }
   else
     {
-      region_nr = lookup_stmt_eh_region (stmt);
-      gcc_assert (region_nr >= 0);
-      is_resx = false;
-      inlinable = inlinable_call_p (stmt);
+      new_lp = NULL;
+      gcc_assert (!change_region);
     }
 
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    fprintf (dump_file, "Redirecting EH edge %i->%i to %i, region %i, resx %i\n",
-            e->src->index, e->dest->index, new_bb->index, region_nr, is_resx);
-  r = redirect_eh_edge_to_label (e, label, is_resx, inlinable, region_nr);
-  new_region_nr = get_eh_region_number (r);
-  if (new_region_nr != region_nr)
-    {
-      if (is_resx)
-        gimple_resx_set_region (stmt, new_region_nr);
-      else
-        {
-         remove_stmt_from_eh_region (stmt);
-         add_stmt_to_eh_region (stmt, new_region_nr);
-        }
-    }
-  e = ssa_redirect_edge (e, new_bb);
-  return e;
-}
-
-static bool mark_eh_edge_found_error;
+  /* Notice when we redirect the last EH edge away from OLD_BB.  */
+  FOR_EACH_EDGE (e, ei, old_bb->preds)
+    if (e != edge_in && (e->flags & EDGE_EH))
+      break;
 
-/* Mark edge make_eh_edge would create for given region by setting it aux
-   field, output error if something goes wrong.  */
-
-static void
-mark_eh_edge (struct eh_region_d *region, void *data)
-{
-  gimple stmt;
-  tree lab;
-  basic_block src, dst;
-  edge e;
-
-  stmt = (gimple) data;
-  lab = get_eh_region_tree_label (region);
-
-  src = gimple_bb (stmt);
-  dst = label_to_block (lab);
-
-  e = find_edge (src, dst);
-  if (!e)
+  if (new_lp)
     {
-      error ("EH edge %i->%i is missing", src->index, dst->index);
-      mark_eh_edge_found_error = true;
+      /* NEW_LP already exists.  If there are still edges into OLD_LP,
+        there's nothing to do with the EH tree.  If there are no more
+        edges into OLD_LP, then we want to remove OLD_LP as it is unused.
+        If CHANGE_REGION is true, then our caller is expecting to remove
+        the landing pad.  */
+      if (e == NULL && !change_region)
+       remove_eh_landing_pad (old_lp);
     }
-  else if (!(e->flags & EDGE_EH))
+  else
     {
-      error ("EH edge %i->%i miss EH flag", src->index, dst->index);
-      mark_eh_edge_found_error = true;
+      /* No correct landing pad exists.  If there are no more edges
+        into OLD_LP, then we can simply re-use the existing landing pad.
+        Otherwise, we have to create a new landing pad.  */
+      if (e == NULL)
+       {
+         EH_LANDING_PAD_NR (old_lp->post_landing_pad) = 0;
+         new_lp = old_lp;
+       }
+      else
+       new_lp = gen_eh_landing_pad (old_lp->region);
+      new_lp->post_landing_pad = new_label;
+      EH_LANDING_PAD_NR (new_label) = new_lp->index;
     }
-  else if (e->aux)
+
+  /* Maybe move the throwing statement to the new region.  */
+  if (old_lp != new_lp)
     {
-      /* ??? might not be mistake.  */
-      error ("EH edge %i->%i has duplicated regions", src->index, dst->index);
-      mark_eh_edge_found_error = true;
+      remove_stmt_from_eh_lp (throw_stmt);
+      add_stmt_to_eh_lp (throw_stmt, new_lp->index);
     }
-  else
-    e->aux = (void *)1;
 }
 
-/* Verify that BB containing STMT as the last statement, has precisely the
-   edges that make_eh_edges would create.  */
+/* Redirect EH edge E to NEW_BB.  */
 
-bool
-verify_eh_edges (gimple stmt)
+edge
+redirect_eh_edge (edge edge_in, basic_block new_bb)
 {
-  int region_nr;
-  bool is_resx;
-  basic_block bb = gimple_bb (stmt);
-  edge_iterator ei;
-  edge e;
-  bool inlinable = false;
+  redirect_eh_edge_1 (edge_in, new_bb, false);
+  return ssa_redirect_edge (edge_in, new_bb);
+}
 
-  FOR_EACH_EDGE (e, ei, bb->succs)
-    gcc_assert (!e->aux);
-  mark_eh_edge_found_error = false;
-  if (gimple_code (stmt) == GIMPLE_RESX)
-    {
-      region_nr = gimple_resx_region (stmt);
-      is_resx = true;
-    }
-  else
-    {
-      region_nr = lookup_stmt_eh_region (stmt);
-      if (region_nr < 0)
-       {
-         FOR_EACH_EDGE (e, ei, bb->succs)
-           if (e->flags & EDGE_EH)
-             {
-               error ("BB %i can not throw but has EH edges", bb->index);
-               return true;
-             }
-          return false;
-       }
-      if (!stmt_could_throw_p (stmt))
-       {
-         error ("BB %i last statement has incorrectly set region", bb->index);
-         return true;
-       }
-      inlinable = inlinable_call_p (stmt);
-      is_resx = false;
-    }
+/* This is a subroutine of gimple_redirect_edge_and_branch.  Update the
+   labels for redirecting a non-fallthru EH_DISPATCH edge E to NEW_BB.
+   The actual edge update will happen in the caller.  */
 
-  foreach_reachable_handler (region_nr, is_resx, inlinable, mark_eh_edge, stmt);
-  FOR_EACH_EDGE (e, ei, bb->succs)
+void
+redirect_eh_dispatch_edge (gimple stmt, edge e, basic_block new_bb)
+{
+  tree new_lab = gimple_block_label (new_bb);
+  bool any_changed = false;
+  basic_block old_bb;
+  eh_region r;
+  eh_catch c;
+
+  r = get_eh_region_from_number (gimple_eh_dispatch_region (stmt));
+  switch (r->type)
     {
-      if ((e->flags & EDGE_EH) && !e->aux)
+    case ERT_TRY:
+      for (c = r->u.eh_try.first_catch; c ; c = c->next_catch)
        {
-         error ("unnecessary EH edge %i->%i", bb->index, e->dest->index);
-         mark_eh_edge_found_error = true;
-         return true;
+         old_bb = label_to_block (c->label);
+         if (old_bb == e->dest)
+           {
+             c->label = new_lab;
+             any_changed = true;
+           }
        }
-      e->aux = NULL;
+      break;
+
+    case ERT_ALLOWED_EXCEPTIONS:
+      old_bb = label_to_block (r->u.allowed.label);
+      gcc_assert (old_bb == e->dest);
+      r->u.allowed.label = new_lab;
+      any_changed = true;
+      break;
+
+    default:
+      gcc_unreachable ();
     }
 
-  return mark_eh_edge_found_error;
+  gcc_assert (any_changed);
 }
-
 \f
 /* Helper function for operation_could_trap_p and stmt_could_throw_p.  */
 
@@ -2307,7 +2345,7 @@ tree_could_trap_p (tree expr)
 
   if (!expr)
     return false;
+
   code = TREE_CODE (expr);
   t = TREE_TYPE (expr);
 
@@ -2349,20 +2387,16 @@ tree_could_trap_p (tree expr)
       base = TREE_OPERAND (expr, 0);
       if (tree_could_trap_p (base))
        return true;
-
       if (TREE_THIS_NOTRAP (expr))
        return false;
-
       return !range_in_array_bounds_p (expr);
 
     case ARRAY_REF:
       base = TREE_OPERAND (expr, 0);
       if (tree_could_trap_p (base))
        return true;
-
       if (TREE_THIS_NOTRAP (expr))
        return false;
-
       return !in_array_bounds_p (expr);
 
     case INDIRECT_REF:
@@ -2373,7 +2407,6 @@ tree_could_trap_p (tree expr)
     case ASM_EXPR:
       return TREE_THIS_VOLATILE (expr);
 
-
     case CALL_EXPR:
       t = get_callee_fndecl (expr);
       /* Assume that calls to weak functions may trap.  */
@@ -2440,35 +2473,33 @@ stmt_could_throw_1_p (gimple stmt)
 bool
 stmt_could_throw_p (gimple stmt)
 {
-  enum gimple_code code;
-
   if (!flag_exceptions)
     return false;
 
   /* The only statements that can throw an exception are assignments,
-     conditionals, calls and asms.  */
-  code = gimple_code (stmt);
-  if (code != GIMPLE_ASSIGN
-      && code != GIMPLE_COND
-      && code != GIMPLE_CALL
-      && code != GIMPLE_ASM)
-    return false;
+     conditionals, calls, resx, and asms.  */
+  switch (gimple_code (stmt))
+    {
+    case GIMPLE_RESX:
+      return true;
 
-  /* If exceptions can only be thrown by function calls and STMT is not a
-     GIMPLE_CALL, the statement cannot throw.  */
-  if (!flag_non_call_exceptions && code != GIMPLE_CALL)
-    return false;
+    case GIMPLE_CALL:
+      return !gimple_call_nothrow_p (stmt);
 
-  if (code == GIMPLE_ASSIGN || code == GIMPLE_COND)
-    return stmt_could_throw_1_p (stmt);
-  else if (is_gimple_call (stmt))
-    return (gimple_call_flags (stmt) & ECF_NOTHROW) == 0;
-  else if (gimple_code (stmt) == GIMPLE_ASM)
-    return (gimple_asm_volatile_p (stmt));
-  else
-    gcc_unreachable ();
+    case GIMPLE_ASSIGN:
+    case GIMPLE_COND:
+      if (!flag_non_call_exceptions)
+        return false;
+      return stmt_could_throw_1_p (stmt);
 
-  return false;
+    case GIMPLE_ASM:
+      if (!flag_non_call_exceptions)
+        return false;
+      return gimple_asm_volatile_p (stmt);
+
+    default:
+      return false;
+    }
 }
 
 
@@ -2482,8 +2513,8 @@ tree_could_throw_p (tree t)
   if (TREE_CODE (t) == MODIFY_EXPR)
     {
       if (flag_non_call_exceptions
-         && tree_could_trap_p (TREE_OPERAND (t, 0)))
-       return true;
+          && tree_could_trap_p (TREE_OPERAND (t, 0)))
+        return true;
       t = TREE_OPERAND (t, 1);
     }
 
@@ -2502,25 +2533,13 @@ tree_could_throw_p (tree t)
 bool
 stmt_can_throw_external (gimple stmt)
 {
-  int region_nr;
-  bool is_resx = false;
-  bool inlinable_call = false;
+  int lp_nr;
 
   if (!stmt_could_throw_p (stmt))
     return false;
 
-  if (gimple_code (stmt) == GIMPLE_RESX)
-    {
-      region_nr = gimple_resx_region (stmt);
-      is_resx = true;
-    }
-  else
-    region_nr = lookup_stmt_eh_region (stmt);
-
-  if (region_nr < 0)
-    return true;
-
-  return can_throw_external_1 (region_nr, is_resx, inlinable_call);
+  lp_nr = lookup_stmt_eh_lp (stmt);
+  return lp_nr == 0;
 }
 
 /* Return true if STMT can throw an exception that is caught within
@@ -2529,49 +2548,56 @@ stmt_can_throw_external (gimple stmt)
 bool
 stmt_can_throw_internal (gimple stmt)
 {
-  int region_nr;
-  bool is_resx = false;
-  bool inlinable_call = false;
-
-  if (gimple_code (stmt) == GIMPLE_RESX)
-    {
-      region_nr = gimple_resx_region (stmt);
-      is_resx = true;
-    }
-  else
-    {
-      region_nr = lookup_stmt_eh_region (stmt);
-      inlinable_call = inlinable_call_p (stmt);
-    }
+  int lp_nr;
 
-  if (region_nr < 0)
+  if (!stmt_could_throw_p (stmt))
     return false;
 
-  return can_throw_internal_1 (region_nr, is_resx, inlinable_call);
+  lp_nr = lookup_stmt_eh_lp (stmt);
+  return lp_nr > 0;
+}
+
+/* Given a statement STMT in IFUN, if STMT can no longer throw, then
+   remove any entry it might have from the EH table.  Return true if
+   any change was made.  */
+
+bool
+maybe_clean_eh_stmt_fn (struct function *ifun, gimple stmt)
+{
+  if (stmt_could_throw_p (stmt))
+    return false;
+  return remove_stmt_from_eh_lp_fn (ifun, stmt);
 }
 
+/* Likewise, but always use the current function.  */
+
+bool
+maybe_clean_eh_stmt (gimple stmt)
+{
+  return maybe_clean_eh_stmt_fn (cfun, stmt);
+}
 
 /* Given a statement OLD_STMT and a new statement NEW_STMT that has replaced
    OLD_STMT in the function, remove OLD_STMT from the EH table and put NEW_STMT
    in the table if it should be in there.  Return TRUE if a replacement was
    done that my require an EH edge purge.  */
 
-bool 
-maybe_clean_or_replace_eh_stmt (gimple old_stmt, gimple new_stmt) 
+bool
+maybe_clean_or_replace_eh_stmt (gimple old_stmt, gimple new_stmt)
 {
-  int region_nr = lookup_stmt_eh_region (old_stmt);
+  int lp_nr = lookup_stmt_eh_lp (old_stmt);
 
-  if (region_nr >= 0)
+  if (lp_nr != 0)
     {
       bool new_stmt_could_throw = stmt_could_throw_p (new_stmt);
 
       if (new_stmt == old_stmt && new_stmt_could_throw)
        return false;
 
-      remove_stmt_from_eh_region (old_stmt);
+      remove_stmt_from_eh_lp (old_stmt);
       if (new_stmt_could_throw)
        {
-         add_stmt_to_eh_region (new_stmt, region_nr);
+         add_stmt_to_eh_lp (new_stmt, lp_nr);
          return false;
        }
       else
@@ -2580,6 +2606,70 @@ maybe_clean_or_replace_eh_stmt (gimple old_stmt, gimple new_stmt)
 
   return false;
 }
+
+/* Given a statement OLD_STMT in OLD_FUN and a duplicate statment NEW_STMT
+   in NEW_FUN, copy the EH table data from OLD_STMT to NEW_STMT.  The MAP
+   operand is the return value of duplicate_eh_regions.  */
+
+bool
+maybe_duplicate_eh_stmt_fn (struct function *new_fun, gimple new_stmt,
+                           struct function *old_fun, gimple old_stmt,
+                           struct pointer_map_t *map, int default_lp_nr)
+{
+  int old_lp_nr, new_lp_nr;
+  void **slot;
+
+  if (!stmt_could_throw_p (new_stmt))
+    return false;
+
+  old_lp_nr = lookup_stmt_eh_lp_fn (old_fun, old_stmt);
+  if (old_lp_nr == 0)
+    {
+      if (default_lp_nr == 0)
+       return false;
+      new_lp_nr = default_lp_nr;
+    }
+  else if (old_lp_nr > 0)
+    {
+      eh_landing_pad old_lp, new_lp;
+
+      old_lp = VEC_index (eh_landing_pad, old_fun->eh->lp_array, old_lp_nr);
+      slot = pointer_map_contains (map, old_lp);
+      new_lp = (eh_landing_pad) *slot;
+      new_lp_nr = new_lp->index;
+    }
+  else
+    {
+      eh_region old_r, new_r;
+
+      old_r = VEC_index (eh_region, old_fun->eh->region_array, -old_lp_nr);
+      slot = pointer_map_contains (map, old_r);
+      new_r = (eh_region) *slot;
+      new_lp_nr = -new_r->index;
+    }
+
+  add_stmt_to_eh_lp_fn (new_fun, new_stmt, new_lp_nr);
+  return true;
+}
+
+/* Similar, but both OLD_STMT and NEW_STMT are within the current function,
+   and thus no remapping is required.  */
+
+bool
+maybe_duplicate_eh_stmt (gimple new_stmt, gimple old_stmt)
+{
+  int lp_nr;
+
+  if (!stmt_could_throw_p (new_stmt))
+    return false;
+
+  lp_nr = lookup_stmt_eh_lp (old_stmt);
+  if (lp_nr == 0)
+    return false;
+
+  add_stmt_to_eh_lp (new_stmt, lp_nr);
+  return true;
+}
 \f
 /* Returns TRUE if oneh and twoh are exception handlers (gimple_try_cleanup of
    GIMPLE_TRY) that are similar enough to be considered the same.  Currently
@@ -2616,7 +2706,7 @@ same_handler_p (gimple_seq oneh, gimple_seq twoh)
 
   for (ai = 0; ai < gimple_call_num_args (ones); ++ai)
     if (!operand_equal_p (gimple_call_arg (ones, ai),
-                         gimple_call_arg (twos, ai), 0))
+                          gimple_call_arg (twos, ai), 0))
       return false;
 
   return true;
@@ -2715,12 +2805,18 @@ refactor_eh (void)
   return 0;
 }
 
+static bool
+gate_refactor_eh (void)
+{
+  return flag_exceptions != 0;
+}
+
 struct gimple_opt_pass pass_refactor_eh =
 {
  {
   GIMPLE_PASS,
   "ehopt",                             /* name */
-  NULL,                                        /* gate */
+  gate_refactor_eh,                    /* gate */
   refactor_eh,                         /* execute */
   NULL,                                        /* sub */
   NULL,                                        /* next */
@@ -2733,512 +2829,919 @@ struct gimple_opt_pass pass_refactor_eh =
   TODO_dump_func                       /* todo_flags_finish */
  }
 };
+\f
+/* At the end of gimple optimization, we can lower RESX.  */
 
-/* Walk statements, see what regions are really references and remove unreachable ones.  */
-
-static void
-tree_remove_unreachable_handlers (void)
+static bool
+lower_resx (basic_block bb, gimple stmt, struct pointer_map_t *mnt_map)
 {
-  sbitmap reachable, contains_stmt;
-  VEC(int,heap) * label_to_region;
-  basic_block bb;
+  int lp_nr;
+  eh_region src_r, dst_r;
+  gimple_stmt_iterator gsi;
+  gimple x;
+  tree fn, src_nr;
+  bool ret = false;
 
-  label_to_region = label_to_region_map ();
-  reachable = sbitmap_alloc (num_eh_regions ());
-  sbitmap_zero (reachable);
-  contains_stmt = sbitmap_alloc (num_eh_regions ());
-  sbitmap_zero (contains_stmt);
+  lp_nr = lookup_stmt_eh_lp (stmt);
+  if (lp_nr != 0)
+    dst_r = get_eh_region_from_lp_number (lp_nr);
+  else
+    dst_r = NULL;
 
-  FOR_EACH_BB (bb)
-  {
-    gimple_stmt_iterator gsi;
-    int region;
-    bool has_eh_preds = bb_has_eh_pred (bb);
+  src_r = get_eh_region_from_number (gimple_resx_region (stmt));
+  src_nr = build_int_cst (NULL, src_r->index);
+  gsi = gsi_last_bb (bb);
 
-    for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
-      {
-       gimple stmt = gsi_stmt (gsi);
+  if (dst_r)
+    {
+      /* When we have a destination region, we resolve this by copying
+        the excptr and filter values into place, and changing the edge
+        to immediately after the landing pad.  */
+      edge e;
 
-       if (gimple_code (stmt) == GIMPLE_LABEL && has_eh_preds)
-         {
-           int uid = LABEL_DECL_UID (gimple_label_label (stmt));
-           int region;
+      if (lp_nr < 0)
+       {
+         basic_block new_bb;
+         void **slot;
+         tree lab;
 
-           for (region = VEC_index (int, label_to_region, uid);
-                region; region = get_next_region_sharing_label (region))
-             SET_BIT (reachable, region);
-         }
-       if (gimple_code (stmt) == GIMPLE_RESX)
-         SET_BIT (reachable,
-                  VEC_index (eh_region, cfun->eh->region_array,
-                             gimple_resx_region (stmt))->region_number);
-       if ((region = lookup_stmt_eh_region (stmt)) >= 0)
-         SET_BIT (contains_stmt, region);
-      }
-  }
+         /* We are resuming into a MUST_NOT_CALL region.  Expand a call to
+            the failure decl into a new block, if needed.  */
+         gcc_assert (dst_r->type == ERT_MUST_NOT_THROW);
 
-  if (dump_file)
-    {
-      fprintf (dump_file, "Before removal of unreachable regions:\n");
-      dump_eh_tree (dump_file, cfun);
-      fprintf (dump_file, "Reachable regions: ");
-      dump_sbitmap_file (dump_file, reachable);
-      fprintf (dump_file, "Regions containing insns: ");
-      dump_sbitmap_file (dump_file, contains_stmt);
-    }
+         slot = pointer_map_contains (mnt_map, dst_r);
+         if (slot == NULL)
+           {
+             gimple_stmt_iterator gsi2;
 
-  remove_unreachable_regions (reachable, contains_stmt);
-  sbitmap_free (reachable);
-  sbitmap_free (contains_stmt);
-  VEC_free (int, heap, label_to_region);
-  if (dump_file)
-    {
-      fprintf (dump_file, "\n\nAfter removal of unreachable regions:\n");
-      dump_eh_tree (dump_file, cfun);
-      fprintf (dump_file, "\n\n");
-    }
-}
+             new_bb = create_empty_bb (bb);
+             lab = gimple_block_label (new_bb);
+             gsi2 = gsi_start_bb (new_bb);
 
-/* Pattern match emtpy EH receiver looking like:
-  
-   save_filt.6352_662 = [filter_expr] <<<filter object>>>;
-   save_eptr.6351_663 = [exc_ptr_expr] <<<exception object>>>;
-   <<<exception object>>> = save_eptr.6351_663;
-   <<<filter object>>> = save_filt.6352_662;
-   resx 1
+             fn = dst_r->u.must_not_throw.failure_decl;
+             x = gimple_build_call (fn, 0);
+             gimple_set_location (x, dst_r->u.must_not_throw.failure_loc);
+             gsi_insert_after (&gsi2, x, GSI_CONTINUE_LINKING);
 
-   And various minor variants after DCE or copy propagation.
- */
+             slot = pointer_map_insert (mnt_map, dst_r);
+             *slot = lab;
+           }
+         else
+           {
+             lab = (tree) *slot;
+             new_bb = label_to_block (lab);
+           }
 
-static int
-tree_empty_eh_handler_p (basic_block bb)
-{
-  gimple_stmt_iterator gsi;
-  int region;
-  edge_iterator ei;
-  edge e;
-  use_operand_p imm_use;
-  gimple use_stmt;
-  bool found = false;
+         gcc_assert (EDGE_COUNT (bb->succs) == 0);
+         e = make_edge (bb, new_bb, EDGE_FALLTHRU);
+         e->count = bb->count;
+         e->probability = REG_BR_PROB_BASE;
+       }
+      else
+       {
+         edge_iterator ei;
+         tree dst_nr = build_int_cst (NULL, dst_r->index);
 
-  gsi = gsi_last_bb (bb);
+         fn = implicit_built_in_decls[BUILT_IN_EH_COPY_VALUES];
+         x = gimple_build_call (fn, 2, dst_nr, src_nr);
+         gsi_insert_before (&gsi, x, GSI_SAME_STMT);
 
-  /* RESX  */
-  if (gsi_end_p (gsi))
-    return 0;
-  if (gimple_code (gsi_stmt (gsi)) != GIMPLE_RESX)
-    return 0;
-  region = gimple_resx_region (gsi_stmt (gsi));
+         /* Update the flags for the outgoing edge.  */
+         e = single_succ_edge (bb);
+         gcc_assert (e->flags & EDGE_EH);
+         e->flags = (e->flags & ~EDGE_EH) | EDGE_FALLTHRU;
 
-  /* filter_object set.  */
-  gsi_prev_nondebug (&gsi);
-  if (gsi_end_p (gsi))
-    return 0;
-  if (gimple_code (gsi_stmt (gsi)) == GIMPLE_ASSIGN)
-    {
-      tree filter_tmp;
-      tree exc_ptr_tmp;
+         /* If there are no more EH users of the landing pad, delete it.  */
+         FOR_EACH_EDGE (e, ei, e->dest->preds)
+           if (e->flags & EDGE_EH)
+             break;
+         if (e == NULL)
+           {
+             eh_landing_pad lp = get_eh_landing_pad_from_number (lp_nr);
+             remove_eh_landing_pad (lp);
+           }
+       }
 
-      if (TREE_CODE (gimple_assign_lhs (gsi_stmt (gsi))) != FILTER_EXPR)
-       return 0;
-      filter_tmp = gimple_assign_rhs1 (gsi_stmt (gsi));
+      ret = true;
+    }
+  else
+    {
+      tree var;
 
-      /* filter_object set.  */
-      gsi_prev_nondebug (&gsi);
-      if (gsi_end_p (gsi))
-       return 0;
-      if (gimple_code (gsi_stmt (gsi)) != GIMPLE_ASSIGN)
-       return 0;
-      if (TREE_CODE (gimple_assign_lhs (gsi_stmt (gsi))) != EXC_PTR_EXPR)
-       return 0;
-      exc_ptr_tmp = gimple_assign_rhs1 (gsi_stmt (gsi));
-
-      /* exc_ptr get.  */
-      if (TREE_CODE (exc_ptr_tmp) != EXC_PTR_EXPR)
-       {
-         gsi_prev_nondebug (&gsi);
-         if (gsi_end_p (gsi))
-           return 0;
-         if (gimple_code (gsi_stmt (gsi)) != GIMPLE_ASSIGN)
-           return 0;
-         if (TREE_CODE (gimple_assign_rhs1 (gsi_stmt (gsi))) != EXC_PTR_EXPR)
-           return 0;
-         if (exc_ptr_tmp != gimple_assign_lhs (gsi_stmt (gsi)))
-           return 0;
-         if (!single_imm_use (exc_ptr_tmp, &imm_use, &use_stmt))
-           return 0;
-       }
+      /* When we don't have a destination region, this exception escapes
+        up the call chain.  We resolve this by generating a call to the
+        _Unwind_Resume library function.  */
 
-      /* filter_object get.  */
-      if (TREE_CODE (filter_tmp) != FILTER_EXPR)
+      /* ??? The ARM EABI redefines _Unwind_Resume as __cxa_end_cleanup
+        with no arguments for C++ and Java.  Check for that.  */
+      switch (targetm.arm_eabi_unwinder)
        {
-         gsi_prev_nondebug (&gsi);
-         if (gsi_end_p (gsi))
-           return 0;
-         if (gimple_code (gsi_stmt (gsi)) != GIMPLE_ASSIGN)
-           return 0;
-         if (TREE_CODE (gimple_assign_rhs1 (gsi_stmt (gsi))) != FILTER_EXPR)
-           return 0;
-         if (filter_tmp != gimple_assign_lhs (gsi_stmt (gsi)))
-           return 0;
-         if (!single_imm_use (filter_tmp, &imm_use, &use_stmt))
-           return 0;
+       default:
+         fn = implicit_built_in_decls[BUILT_IN_UNWIND_RESUME];
+         if (TYPE_ARG_TYPES (TREE_TYPE (fn)) == void_list_node)
+           {
+             x = gimple_build_call (fn, 0);
+             gsi_insert_before (&gsi, x, GSI_SAME_STMT);
+             break;
+           }
+         /* FALLTHRU */
+
+       case 0:
+         fn = implicit_built_in_decls[BUILT_IN_EH_POINTER];
+         x = gimple_build_call (fn, 1, src_nr);
+         var = create_tmp_var (ptr_type_node, NULL);
+         var = make_ssa_name (var, x);
+         gimple_call_set_lhs (x, var);
+         gsi_insert_before (&gsi, x, GSI_SAME_STMT);
+
+         fn = implicit_built_in_decls[BUILT_IN_UNWIND_RESUME];
+         x = gimple_build_call (fn, 1, var);
+         gsi_insert_before (&gsi, x, GSI_SAME_STMT);
+         break;
        }
 
-      /* label.  */
-      gsi_prev_nondebug (&gsi);
-      if (gsi_end_p (gsi))
-       return 0;
+      gcc_assert (EDGE_COUNT (bb->succs) == 0);
     }
-  if (gimple_code (gsi_stmt (gsi)) != GIMPLE_LABEL)
-    return 0;
 
-  /* Be sure that there is at least on EH region reaching the block directly.
-     After EH edge redirection, it is possible that block is reached by one handler
-     but resumed by different.  */
-  FOR_EACH_EDGE (e, ei, bb->preds)
-    if ((e->flags & EDGE_EH))
-      found = true;
-  if (found)
-    return region;
-  return 0;
+  gsi_remove (&gsi, true);
+
+  return ret;
 }
 
-/* Return true if it is possible to remove basic block BB and propagate
-   through PHIs.  
+static unsigned
+execute_lower_resx (void)
+{
+  basic_block bb;
+  struct pointer_map_t *mnt_map;
+  bool dominance_invalidated = false;
+  bool any_rewritten = false;
 
-   This means that every PHI in BB has all uses such that they are PHIs
-   of basic blocks reachable througt BB and they appears only in use
-   reachable by the edge from BB to the block contianing the use.  
-   
-   This is same as in merge-phi code, but in slightly more general setting
-   because BB can have multiple successors.  */
+  mnt_map = pointer_map_create ();
 
-static bool
-all_phis_safe_to_merge (basic_block bb)
-{
-  gimple_stmt_iterator si;
-  bool ok = true;
-
-  for (si = gsi_start_phis (bb); !gsi_end_p (si); gsi_next (&si))
-    {
-      gimple phi = gsi_stmt (si);
-      tree result = gimple_phi_result (phi);
-      gimple stmt;
-      use_operand_p imm_use;
-      imm_use_iterator imm_iter;
-
-      /* If the PHI's result is never used, then we can just
-        ignore it.  */
-      if (has_zero_uses (result))
-        continue;
-      /* We can always rebuild virtuals if needed.  */
-      if (!is_gimple_reg (result))
-       continue;
-      FOR_EACH_IMM_USE_STMT (stmt, imm_iter, result)
-        {
-         if (gimple_code (stmt) != GIMPLE_PHI)
-           {
-             if (dump_file && (dump_flags & TDF_DETAILS))
-               fprintf (dump_file,
-                        "PHI result has use in non-PHI statement.\n");
-             ok = false;
-             BREAK_FROM_IMM_USE_STMT (imm_iter);
-           }
-         else
-            FOR_EACH_IMM_USE_ON_STMT (imm_use, imm_iter)
-             {
-               edge e;
-              e = gimple_phi_arg_edge (stmt, PHI_ARG_INDEX_FROM_USE (imm_use));
-              if (e->src != bb)
-                {
-                 if (dump_file && (dump_flags & TDF_DETAILS))
-                   fprintf (dump_file, "PHI has use in PHI not reached from"
-                            "empty cleanup itself.\n");
-                 ok = false;
-                 break;
-                }
-             }
-          if (!ok)
-            BREAK_FROM_IMM_USE_STMT (imm_iter);
-        }
-       if (!ok)
-         return false;
+  FOR_EACH_BB (bb)
+    {
+      gimple last = last_stmt (bb);
+      if (last && is_gimple_resx (last))
+       {
+         dominance_invalidated |= lower_resx (bb, last, mnt_map);
+         any_rewritten = true;
+       }
+    }
+
+  pointer_map_destroy (mnt_map);
+
+  if (dominance_invalidated)
+    {
+      free_dominance_info (CDI_DOMINATORS);
+      free_dominance_info (CDI_POST_DOMINATORS);
     }
-  return ok;
-}
 
-static bool dominance_info_invalidated;
+  return any_rewritten ? TODO_update_ssa_only_virtuals : 0;
+}
 
-/* Information to pass into make_eh_edge_and_update_phi.  */
+static bool
+gate_lower_ehcontrol (void)
+{
+  return cfun->eh->region_tree != NULL;
+}
 
-struct update_info
+struct gimple_opt_pass pass_lower_resx =
 {
-  basic_block bb_to_remove, bb;
-  edge edge_to_remove;
+ {
+  GIMPLE_PASS,
+  "resx",                              /* name */
+  gate_lower_ehcontrol,                        /* gate */
+  execute_lower_resx,                  /* execute */
+  NULL,                                        /* sub */
+  NULL,                                        /* next */
+  0,                                   /* static_pass_number */
+  TV_TREE_EH,                          /* tv_id */
+  PROP_gimple_lcf,                     /* properties_required */
+  0,                                   /* properties_provided */
+  0,                                   /* properties_destroyed */
+  0,                                   /* todo_flags_start */
+  TODO_dump_func | TODO_verify_flow    /* todo_flags_finish */
+ }
 };
 
-/* DATA points to update-info structure.
-   Like make_eh_edge create EH edge from DATA->bb to basic block containing
-   handler of REGION.  In addition also update PHI operands by copying
-   operands from DATA->bb_to_remove.  */
+
+/* At the end of inlining, we can lower EH_DISPATCH.  */
 
 static void
-make_eh_edge_and_update_phi (struct eh_region_d *region, void *data)
+lower_eh_dispatch (basic_block src, gimple stmt)
 {
-  struct update_info *info = (struct update_info *) data;
-  edge e, e2;
-  tree lab;
-  basic_block src, dst;
-  gimple_stmt_iterator si;
+  gimple_stmt_iterator gsi;
+  int region_nr;
+  eh_region r;
+  tree filter, fn;
+  gimple x;
 
-  lab = get_eh_region_tree_label (region);
+  region_nr = gimple_eh_dispatch_region (stmt);
+  r = get_eh_region_from_number (region_nr);
 
-  src = info->bb;
-  dst = label_to_block (lab);
+  gsi = gsi_last_bb (src);
 
-  e = find_edge (src, dst);
-  if (e)
+  switch (r->type)
     {
-      gcc_assert (e->flags & EDGE_EH);
-      e->aux = e;
-      return;
-    }
-  dominance_info_invalidated = true;
-  e2 = find_edge (info->bb_to_remove, dst);
-  e = make_edge (src, dst, EDGE_EH);
-  e->aux = e;
-  gcc_assert (e2);
-  for (si = gsi_start_phis (dst); !gsi_end_p (si); gsi_next (&si))
-    {
-      gimple phi = gsi_stmt (si);
-      tree use = USE_FROM_PTR (PHI_ARG_DEF_PTR_FROM_EDGE (phi, e2));
-      gimple def = (TREE_CODE (use) == SSA_NAME
-                   ? SSA_NAME_DEF_STMT (use) : NULL);
+    case ERT_TRY:
+      {
+       VEC (tree, heap) *labels = NULL;
+       tree default_label = NULL;
+       eh_catch c;
+       edge_iterator ei;
+       edge e;
+
+       /* Collect the labels for a switch.  Zero the post_landing_pad
+          field becase we'll no longer have anything keeping these labels
+          in existance and the optimizer will be free to merge these
+          blocks at will.  */
+       for (c = r->u.eh_try.first_catch; c ; c = c->next_catch)
+         {
+           tree tp_node, flt_node, lab = c->label;
 
-      if (def && gimple_bb (def) == info->bb_to_remove)
-        {
-         use = USE_FROM_PTR (PHI_ARG_DEF_PTR_FROM_EDGE (def,
-                                                        info->edge_to_remove));
-         gcc_assert (info->bb_to_remove == info->edge_to_remove->dest);
-          def = TREE_CODE (use) == SSA_NAME ? SSA_NAME_DEF_STMT (use) : NULL;
-         gcc_assert (!def
-                     || gimple_bb (def) != info->bb_to_remove
-                     || !is_gimple_reg (use));
-        }
-      SET_USE (PHI_ARG_DEF_PTR_FROM_EDGE (phi, e), use);
+           c->label = NULL;
+           tp_node = c->type_list;
+           flt_node = c->filter_list;
+
+           if (tp_node == NULL)
+             {
+               default_label = lab;
+               break;
+             }
+           do
+             {
+               tree t = build3 (CASE_LABEL_EXPR, void_type_node,
+                                TREE_VALUE (flt_node), NULL, lab);
+               VEC_safe_push (tree, heap, labels, t);
+
+               tp_node = TREE_CHAIN (tp_node);
+               flt_node = TREE_CHAIN (flt_node);
+             }
+           while (tp_node);
+         }
+
+       /* Clean up the edge flags.  */
+       FOR_EACH_EDGE (e, ei, src->succs)
+         {
+           if (e->flags & EDGE_FALLTHRU)
+             {
+               /* If there was no catch-all, use the fallthru edge.  */
+               if (default_label == NULL)
+                 default_label = gimple_block_label (e->dest);
+               e->flags &= ~EDGE_FALLTHRU;
+             }
+         }
+       gcc_assert (default_label != NULL);
+
+       /* Don't generate a switch if there's only a default case.
+          This is common in the form of try { A; } catch (...) { B; }.  */
+       if (labels == NULL)
+         {
+           e = single_succ_edge (src);
+           e->flags |= EDGE_FALLTHRU;
+         }
+       else
+         {
+           fn = implicit_built_in_decls[BUILT_IN_EH_FILTER];
+           x = gimple_build_call (fn, 1, build_int_cst (NULL, region_nr));
+           filter = create_tmp_var (TREE_TYPE (TREE_TYPE (fn)), NULL);
+           filter = make_ssa_name (filter, x);
+           gimple_call_set_lhs (x, filter);
+           gsi_insert_before (&gsi, x, GSI_SAME_STMT);
+
+           /* Turn the default label into a default case.  */
+           default_label = build3 (CASE_LABEL_EXPR, void_type_node,
+                                   NULL, NULL, default_label);
+           sort_case_labels (labels);
+
+           x = gimple_build_switch_vec (filter, default_label, labels);
+           gsi_insert_before (&gsi, x, GSI_SAME_STMT);
+
+           VEC_free (tree, heap, labels);
+         }
+      }
+      break;
+
+    case ERT_ALLOWED_EXCEPTIONS:
+      {
+       edge b_e = BRANCH_EDGE (src);
+       edge f_e = FALLTHRU_EDGE (src);
+
+       fn = implicit_built_in_decls[BUILT_IN_EH_FILTER];
+       x = gimple_build_call (fn, 1, build_int_cst (NULL, region_nr));
+       filter = create_tmp_var (TREE_TYPE (TREE_TYPE (fn)), NULL);
+       filter = make_ssa_name (filter, x);
+       gimple_call_set_lhs (x, filter);
+       gsi_insert_before (&gsi, x, GSI_SAME_STMT);
+
+       r->u.allowed.label = NULL;
+       x = gimple_build_cond (EQ_EXPR, filter,
+                              build_int_cst (TREE_TYPE (filter),
+                                             r->u.allowed.filter),
+                              NULL_TREE, NULL_TREE);
+       gsi_insert_before (&gsi, x, GSI_SAME_STMT);
+
+       b_e->flags = b_e->flags | EDGE_TRUE_VALUE;
+        f_e->flags = (f_e->flags & ~EDGE_FALLTHRU) | EDGE_FALSE_VALUE;
+      }
+      break;
+
+    default:
+      gcc_unreachable ();
     }
+
+  /* Replace the EH_DISPATCH with the SWITCH or COND generated above.  */
+  gsi_remove (&gsi, true);
 }
 
-/* Make EH edges corresponding to STMT while updating PHI nodes after removal
-   empty cleanup BB_TO_REMOVE joined to BB containing STMT
-   by EDGE_TO_REMOVE.
+static unsigned
+execute_lower_eh_dispatch (void)
+{
+  basic_block bb;
+  bool any_rewritten = false;
 
-   Return if EDGE_TO_REMOVE was really removed.  It might stay reachable when
-   not all EH regions are cleaned up.  */
+  assign_filter_values ();
 
-static bool
-update_eh_edges (gimple stmt, basic_block bb_to_remove, edge edge_to_remove)
+  FOR_EACH_BB (bb)
+    {
+      gimple last = last_stmt (bb);
+      if (last && gimple_code (last) == GIMPLE_EH_DISPATCH)
+       {
+         lower_eh_dispatch (bb, last);
+         any_rewritten = true;
+       }
+    }
+
+  return any_rewritten ? TODO_update_ssa_only_virtuals : 0;
+}
+
+struct gimple_opt_pass pass_lower_eh_dispatch =
 {
-  int region_nr;
-  bool is_resx;
-  bool inlinable = false;
-  struct update_info info;
-  edge_iterator ei;
-  edge e;
-  int probability_sum = 0;
-  bool removed = false;
+ {
+  GIMPLE_PASS,
+  "ehdisp",                            /* name */
+  gate_lower_ehcontrol,                        /* gate */
+  execute_lower_eh_dispatch,           /* execute */
+  NULL,                                        /* sub */
+  NULL,                                        /* next */
+  0,                                   /* static_pass_number */
+  TV_TREE_EH,                          /* tv_id */
+  PROP_gimple_lcf,                     /* properties_required */
+  0,                                   /* properties_provided */
+  0,                                   /* properties_destroyed */
+  0,                                   /* todo_flags_start */
+  TODO_dump_func | TODO_verify_flow    /* todo_flags_finish */
+ }
+};
+\f
+/* Walk statements, see what regions are really referenced and remove
+   those that are unused.  */
+
+static void
+remove_unreachable_handlers (void)
+{
+  sbitmap r_reachable, lp_reachable;
+  eh_region region;
+  eh_landing_pad lp;
+  basic_block bb;
+  int lp_nr, r_nr;
 
-  info.bb_to_remove = bb_to_remove;
-  info.bb = gimple_bb (stmt);
-  info.edge_to_remove = edge_to_remove;
+  r_reachable = sbitmap_alloc (VEC_length (eh_region, cfun->eh->region_array));
+  lp_reachable
+    = sbitmap_alloc (VEC_length (eh_landing_pad, cfun->eh->lp_array));
+  sbitmap_zero (r_reachable);
+  sbitmap_zero (lp_reachable);
 
-  if (gimple_code (stmt) == GIMPLE_RESX)
+  FOR_EACH_BB (bb)
     {
-      region_nr = gimple_resx_region (stmt);
-      is_resx = true;
+      gimple_stmt_iterator gsi = gsi_start_bb (bb);
+
+      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+       {
+         gimple stmt = gsi_stmt (gsi);
+         lp_nr = lookup_stmt_eh_lp (stmt);
+
+         /* Negative LP numbers are MUST_NOT_THROW regions which
+            are not considered BB enders.  */
+         if (lp_nr < 0)
+           SET_BIT (r_reachable, -lp_nr);
+
+         /* Positive LP numbers are real landing pads, are are BB enders.  */
+         else if (lp_nr > 0)
+           {
+             gcc_assert (gsi_one_before_end_p (gsi));
+             region = get_eh_region_from_lp_number (lp_nr);
+             SET_BIT (r_reachable, region->index);
+             SET_BIT (lp_reachable, lp_nr);
+           }
+       }
     }
-  else
+
+  if (dump_file)
     {
-      region_nr = lookup_stmt_eh_region (stmt);
-      is_resx = false;
-      inlinable = inlinable_call_p (stmt);
+      fprintf (dump_file, "Before removal of unreachable regions:\n");
+      dump_eh_tree (dump_file, cfun);
+      fprintf (dump_file, "Reachable regions: ");
+      dump_sbitmap_file (dump_file, r_reachable);
+      fprintf (dump_file, "Reachable landing pads: ");
+      dump_sbitmap_file (dump_file, lp_reachable);
     }
 
-  /* First add new edges as neccesary.  */
-  foreach_reachable_handler (region_nr, is_resx, inlinable,
-                            make_eh_edge_and_update_phi, &info);
+  for (r_nr = 1;
+       VEC_iterate (eh_region, cfun->eh->region_array, r_nr, region); ++r_nr)
+    if (region && !TEST_BIT (r_reachable, r_nr))
+      {
+       if (dump_file)
+         fprintf (dump_file, "Removing unreachable region %d\n", r_nr);
+       remove_eh_handler (region);
+      }
 
-  /* And remove edges we didn't marked. */
-  for (ei = ei_start (info.bb->succs); (e = ei_safe_edge (ei)); )
+  for (lp_nr = 1;
+       VEC_iterate (eh_landing_pad, cfun->eh->lp_array, lp_nr, lp); ++lp_nr)
+    if (lp && !TEST_BIT (lp_reachable, lp_nr))
+      {
+       if (dump_file)
+         fprintf (dump_file, "Removing unreachable landing pad %d\n", lp_nr);
+       remove_eh_landing_pad (lp);
+      }
+    
+  if (dump_file)
     {
-      if ((e->flags & EDGE_EH) && !e->aux)
-       {
-         dominance_info_invalidated = true;
-         if (e == edge_to_remove)
-           removed = true;
-         remove_edge (e);
-       }
-      else
-        {
-         e->aux = NULL;
-         probability_sum += e->probability;
-         ei_next (&ei);
-       }
+      fprintf (dump_file, "\n\nAfter removal of unreachable regions:\n");
+      dump_eh_tree (dump_file, cfun);
+      fprintf (dump_file, "\n\n");
     }
 
-  /* Make CFG profile more consistent assuming that exception will resume to
-     first available EH handler.  In practice this makes little difference, but
-     we get fewer consistency errors in the dumps.  */
-  if (is_resx && EDGE_COUNT (info.bb->succs) && !probability_sum)
-    EDGE_SUCC (info.bb, 0)->probability = REG_BR_PROB_BASE;
-  return removed;
+  sbitmap_free (r_reachable);
+  sbitmap_free (lp_reachable);
+
+#ifdef ENABLE_CHECKING
+  verify_eh_tree (cfun);
+#endif
+}
+
+/* Remove regions that do not have landing pads.  This assumes
+   that remove_unreachable_handlers has already been run, and
+   that we've just manipulated the landing pads since then.  */
+
+static void
+remove_unreachable_handlers_no_lp (void)
+{
+  eh_region r;
+  int i;
+
+  for (i = 1; VEC_iterate (eh_region, cfun->eh->region_array, i, r); ++i)
+    if (r && r->landing_pads == NULL && r->type != ERT_MUST_NOT_THROW)
+      {
+       if (dump_file)
+         fprintf (dump_file, "Removing unreachable region %d\n", i);
+       remove_eh_handler (r);
+      }
 }
 
-/* Look for basic blocks containing empty exception handler and remove them.
-   This is similar to jump forwarding, just across EH edges.  */
+/* Undo critical edge splitting on an EH landing pad.  Earlier, we
+   optimisticaly split all sorts of edges, including EH edges.  The
+   optimization passes in between may not have needed them; if not,
+   we should undo the split.
+
+   Recognize this case by having one EH edge incoming to the BB and
+   one normal edge outgoing; BB should be empty apart from the
+   post_landing_pad label.
+
+   Note that this is slightly different from the empty handler case
+   handled by cleanup_empty_eh, in that the actual handler may yet
+   have actual code but the landing pad has been separated from the
+   handler.  As such, cleanup_empty_eh relies on this transformation
+   having been done first.  */
 
 static bool
-cleanup_empty_eh (basic_block bb, VEC(int,heap) * label_to_region)
+unsplit_eh (eh_landing_pad lp)
 {
-  int region;
-  gimple_stmt_iterator si;
-  edge_iterator ei;
+  basic_block bb = label_to_block (lp->post_landing_pad);
+  gimple_stmt_iterator gsi;
+  edge e_in, e_out;
+
+  /* Quickly check the edge counts on BB for singularity.  */
+  if (EDGE_COUNT (bb->preds) != 1 || EDGE_COUNT (bb->succs) != 1)
+    return false;
+  e_in = EDGE_PRED (bb, 0);
+  e_out = EDGE_SUCC (bb, 0);
 
-  /* When handler of EH region winds up to be empty, we can safely
-     remove it.  This leads to inner EH regions to be redirected
-     to outer one, if present in function. So we need to rebuild
-     EH edges in all sources.   */
-  if ((region = tree_empty_eh_handler_p (bb))
-      && all_phis_safe_to_merge (bb))
+  /* Input edge must be EH and output edge must be normal.  */
+  if ((e_in->flags & EDGE_EH) == 0 || (e_out->flags & EDGE_EH) != 0)
+    return false;
+
+  /* The block must be empty except for the labels.  */
+  if (!gsi_end_p (gsi_after_labels (bb)))
+    return false;
+
+  /* The destination block must not already have a landing pad
+     for a different region.  */
+  for (gsi = gsi_start_bb (e_out->dest); !gsi_end_p (gsi); gsi_next (&gsi))
     {
-      edge e;
-      bool found = false, removed_some = false, has_non_eh_preds = false;
-      gimple_stmt_iterator gsi;
+      gimple stmt = gsi_stmt (gsi);
+      tree lab;
+      int lp_nr;
 
-      /* Look for all EH regions sharing label of this block.
-         If they are not same as REGION, remove them and replace them
-        by outer region of REGION.  Also note if REGION itself is one
-        of them.  */
+      if (gimple_code (stmt) != GIMPLE_LABEL)
+       break;
+      lab = gimple_label_label (stmt);
+      lp_nr = EH_LANDING_PAD_NR (lab);
+      if (lp_nr && get_eh_region_from_lp_number (lp_nr) != lp->region)
+       return false;
+    }
 
-      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
-        if (gimple_code (gsi_stmt (gsi)) == GIMPLE_LABEL)
-         {
-           int uid = LABEL_DECL_UID (gimple_label_label (gsi_stmt (gsi)));
-           int r = VEC_index (int, label_to_region, uid);
-           int next;
+  /* ??? I can't imagine there would be PHI nodes, since by nature
+     of critical edge splitting this block should never have been
+     a dominance frontier.  If cfg cleanups somehow confuse this,
+     due to single edges in and out we ought to have degenerate PHIs
+     and can easily propagate the PHI arguments.  */
+  gcc_assert (gimple_seq_empty_p (phi_nodes (bb)));
 
-           while (r)
-             {
-               next = get_next_region_sharing_label (r);
-               if (r == region)
-                 found = true;
-               else
-                 {
-                    removed_some = true;
-                    remove_eh_region_and_replace_by_outer_of (r, region);
-                    if (dump_file && (dump_flags & TDF_DETAILS))
-                      fprintf (dump_file, "Empty EH handler %i removed and "
-                               "replaced by %i\n", r, region);
-                 }
-               r = next;
-             }
-         }
-       else
-         break;
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    fprintf (dump_file, "Unsplit EH landing pad %d to block %i.\n",
+            lp->index, e_out->dest->index);
+
+  /* Redirect the edge.  Since redirect_eh_edge_1 expects to be moving
+     a successor edge, humor it.  But do the real CFG change with the
+     predecessor of E_OUT in order to preserve the ordering of arguments
+     to the PHI nodes in E_OUT->DEST.  */
+  redirect_eh_edge_1 (e_in, e_out->dest, false);
+  redirect_edge_pred (e_out, e_in->src);
+  e_out->flags = e_in->flags;
+  e_out->probability = e_in->probability;
+  e_out->count = e_in->count;
+  remove_edge (e_in);
 
-      gcc_assert (found || removed_some);
-      FOR_EACH_EDGE (e, ei, bb->preds)
-       if (!(e->flags & EDGE_EH))
-         has_non_eh_preds = true;
+  return true;
+}
 
-      /* When block is empty EH cleanup, but it is reachable via non-EH code too,
-        we can not remove the region it is resumed via, because doing so will
-        lead to redirection of its RESX edges.
+/* Examine each landing pad block and see if it matches unsplit_eh.  */
 
-        This case will be handled later after edge forwarding if the EH cleanup
-        is really dead.  */
+static bool
+unsplit_all_eh (void)
+{
+  bool changed = false;
+  eh_landing_pad lp;
+  int i;
 
-      if (found && !has_non_eh_preds)
-        {
-          if (dump_file && (dump_flags & TDF_DETAILS))
-            fprintf (dump_file, "Empty EH handler %i removed.\n", region);
-          remove_eh_region (region);
+  for (i = 1; VEC_iterate (eh_landing_pad, cfun->eh->lp_array, i, lp); ++i)
+    if (lp)
+      changed |= unsplit_eh (lp);
+
+  return changed;
+}
+
+/* A subroutine of cleanup_empty_eh.  Redirect all EH edges incoming
+   to OLD_BB to NEW_BB; return true on success, false on failure.
+
+   OLD_BB_OUT is the edge into NEW_BB from OLD_BB, so if we miss any
+   PHI variables from OLD_BB we can pick them up from OLD_BB_OUT.
+   Virtual PHIs may be deleted and marked for renaming.  */
+
+static bool
+cleanup_empty_eh_merge_phis (basic_block new_bb, basic_block old_bb,
+                            edge old_bb_out)
+{
+  gimple_stmt_iterator ngsi, ogsi;
+  edge_iterator ei;
+  edge e;
+  bitmap rename_virts;
+  bitmap ophi_handled;
+
+  FOR_EACH_EDGE (e, ei, old_bb->preds)
+    redirect_edge_var_map_clear (e);
+
+  ophi_handled = BITMAP_ALLOC (NULL);
+  rename_virts = BITMAP_ALLOC (NULL);
+
+  /* First, iterate through the PHIs on NEW_BB and set up the edge_var_map
+     for the edges we're going to move.  */
+  for (ngsi = gsi_start_phis (new_bb); !gsi_end_p (ngsi); gsi_next (&ngsi))
+    {
+      gimple ophi, nphi = gsi_stmt (ngsi);
+      tree nresult, nop;
+
+      nresult = gimple_phi_result (nphi);
+      nop = gimple_phi_arg_def (nphi, old_bb_out->dest_idx);
+
+      /* Find the corresponding PHI in OLD_BB so we can forward-propagate
+        the source ssa_name.  */
+      ophi = NULL;
+      for (ogsi = gsi_start_phis (old_bb); !gsi_end_p (ogsi); gsi_next (&ogsi))
+       {
+         ophi = gsi_stmt (ogsi);
+         if (gimple_phi_result (ophi) == nop)
+           break;
+         ophi = NULL;
        }
-      else if (!removed_some)
-        return false;
 
-      for (ei = ei_start (bb->preds); (e = ei_safe_edge (ei)); )
+      /* If we did find the corresponding PHI, copy those inputs.  */
+      if (ophi)
        {
-         basic_block src = e->src;
-         if (!(e->flags & EDGE_EH))
+         bitmap_set_bit (ophi_handled, SSA_NAME_VERSION (nop));
+         FOR_EACH_EDGE (e, ei, old_bb->preds)
            {
-             ei_next (&ei);
-             continue;
+             location_t oloc;
+             tree oop;
+
+             if ((e->flags & EDGE_EH) == 0)
+               continue;
+             oop = gimple_phi_arg_def (ophi, e->dest_idx);
+             oloc = gimple_phi_arg_location (ophi, e->dest_idx);
+             redirect_edge_var_map_add (e, nresult, oop, oloc);
            }
-         if (stmt_can_throw_internal (last_stmt (src)))
+       }
+      /* If we didn't find the PHI, but it's a VOP, remember to rename
+        it later, assuming all other tests succeed.  */
+      else if (!is_gimple_reg (nresult))
+       bitmap_set_bit (rename_virts, SSA_NAME_VERSION (nresult));
+      /* If we didn't find the PHI, and it's a real variable, we know
+        from the fact that OLD_BB is tree_empty_eh_handler_p that the
+        variable is unchanged from input to the block and we can simply
+        re-use the input to NEW_BB from the OLD_BB_OUT edge.  */
+      else
+       {
+         location_t nloc
+           = gimple_phi_arg_location (nphi, old_bb_out->dest_idx);
+         FOR_EACH_EDGE (e, ei, old_bb->preds)
+           redirect_edge_var_map_add (e, nresult, nop, nloc);
+       }
+    }
+
+  /* Second, verify that all PHIs from OLD_BB have been handled.  If not,
+     we don't know what values from the other edges into NEW_BB to use.  */
+  for (ogsi = gsi_start_phis (old_bb); !gsi_end_p (ogsi); gsi_next (&ogsi))
+    {
+      gimple ophi = gsi_stmt (ogsi);
+      tree oresult = gimple_phi_result (ophi);
+      if (!bitmap_bit_p (ophi_handled, SSA_NAME_VERSION (oresult)))
+       goto fail;
+    }
+
+  /* At this point we know that the merge will succeed.  Remove the PHI
+     nodes for the virtuals that we want to rename.  */
+  if (!bitmap_empty_p (rename_virts))
+    {
+      for (ngsi = gsi_start_phis (new_bb); !gsi_end_p (ngsi); )
+       {
+         gimple nphi = gsi_stmt (ngsi);
+         tree nresult = gimple_phi_result (nphi);
+         if (bitmap_bit_p (rename_virts, SSA_NAME_VERSION (nresult)))
            {
-             if (!update_eh_edges (last_stmt (src), bb, e))
-               ei_next (&ei);
+             mark_virtual_phi_result_for_renaming (nphi);
+             remove_phi_node (&ngsi, true);
            }
          else
-           remove_edge (e);
+           gsi_next (&ngsi);
        }
+    }
 
-      /* Verify that we eliminated all uses of PHI we are going to remove.
-         If we didn't, rebuild SSA on affected variable (this is allowed only
-         for virtuals).  */
-      for (si = gsi_start_phis (bb); !gsi_end_p (si); gsi_next (&si))
-        {
-          gimple phi = gsi_stmt (si);
-          tree result = gimple_phi_result (phi);
-          if (!has_zero_uses (result))
-           {
-              use_operand_p use_p;
-              imm_use_iterator iter;
-             gimple stmt;
+  /* Finally, move the edges and update the PHIs.  */
+  for (ei = ei_start (old_bb->preds); (e = ei_safe_edge (ei)); )
+    if (e->flags & EDGE_EH)
+      {
+       redirect_eh_edge_1 (e, new_bb, true);
+       redirect_edge_succ (e, new_bb);
+       flush_pending_stmts (e);
+      }
+    else
+      ei_next (&ei);
 
-             FOR_EACH_IMM_USE_STMT (stmt, iter, result)
-               {
-                 /* We have use, see if it won't disappear after
-                    removing BB.  */
-                 if (gimple_bb (stmt) == bb)
-                   continue;
-                 if (gimple_code (stmt) == GIMPLE_PHI)
-                   {
-                     bool bad = false;
-
-                     FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
-                       if (gimple_phi_arg_edge (stmt,
-                               PHI_ARG_INDEX_FROM_USE (use_p))->src != bb)
-                         {
-                           bad = true;
-                           break;
-                         }
-
-                     if (!bad)
-                       continue;
-                   }
-
-                 gcc_assert (!is_gimple_reg (result));
-                 mark_sym_for_renaming (SSA_NAME_VAR (result));
-                 /* As we are going to delete this block we will release all
-                    defs which makes the immediate uses on use stmts invalid.
-                    Avoid that by replacing all uses with the bare variable
-                    and updating the stmts.  */
-                 FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
-                   SET_USE (use_p, SSA_NAME_VAR (result));
-                 update_stmt (stmt);
-               }
-           }
-       }
-      if (!ei_safe_edge (ei_start (bb->preds)))
-        delete_basic_block (bb);
+  BITMAP_FREE (ophi_handled);
+  BITMAP_FREE (rename_virts);
+  return true;
+
+ fail:
+  FOR_EACH_EDGE (e, ei, old_bb->preds)
+    redirect_edge_var_map_clear (e);
+  BITMAP_FREE (ophi_handled);
+  BITMAP_FREE (rename_virts);
+  return false;
+}
+
+/* A subroutine of cleanup_empty_eh.  Move a landing pad LP from its
+   old region to NEW_REGION at BB.  */
+
+static void
+cleanup_empty_eh_move_lp (basic_block bb, edge e_out,
+                         eh_landing_pad lp, eh_region new_region)
+{
+  gimple_stmt_iterator gsi;
+  eh_landing_pad *pp;
+
+  for (pp = &lp->region->landing_pads; *pp != lp; pp = &(*pp)->next_lp)
+    continue;
+  *pp = lp->next_lp;
+
+  lp->region = new_region;
+  lp->next_lp = new_region->landing_pads;
+  new_region->landing_pads = lp;
+
+  /* Delete the RESX that was matched within the empty handler block.  */
+  gsi = gsi_last_bb (bb);
+  mark_virtual_ops_for_renaming (gsi_stmt (gsi));
+  gsi_remove (&gsi, true);
+
+  /* Clean up E_OUT for the fallthru.  */
+  e_out->flags = (e_out->flags & ~EDGE_EH) | EDGE_FALLTHRU;
+  e_out->probability = REG_BR_PROB_BASE;
+}
+
+/* A subroutine of cleanup_empty_eh.  Handle more complex cases of
+   unsplitting than unsplit_eh was prepared to handle, e.g. when 
+   multiple incoming edges and phis are involved.  */
+
+static bool
+cleanup_empty_eh_unsplit (basic_block bb, edge e_out, eh_landing_pad olp)
+{
+  gimple_stmt_iterator gsi;
+  eh_landing_pad nlp;
+  tree lab;
+
+  /* We really ought not have totally lost everything following
+     a landing pad label.  Given that BB is empty, there had better
+     be a successor.  */
+  gcc_assert (e_out != NULL);
+
+  /* Look for an EH label in the successor block.  */
+  lab = NULL;
+  for (gsi = gsi_start_bb (e_out->dest); !gsi_end_p (gsi); gsi_next (&gsi))
+    {
+      gimple stmt = gsi_stmt (gsi);
+      if (gimple_code (stmt) != GIMPLE_LABEL)
+       break;
+      lab = gimple_label_label (stmt);
+      if (EH_LANDING_PAD_NR (lab))
+       goto found;
+    }
+  return false;
+ found:
+
+  /* The other label had better be part of the same EH region.  Given that
+     we've not lowered RESX, there should be no way to have a totally empty
+     landing pad that crosses to another EH region.  */
+  nlp = get_eh_landing_pad_from_number (EH_LANDING_PAD_NR (lab));
+  gcc_assert (nlp->region == olp->region);
+
+  /* Attempt to move the PHIs into the successor block.  */
+  if (cleanup_empty_eh_merge_phis (e_out->dest, bb, e_out))
+    {
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       fprintf (dump_file,
+                "Unsplit EH landing pad %d to block %d via lp %d.\n",
+                olp->index, e_out->dest->index, nlp->index);
+
+      remove_eh_landing_pad (olp);
+      return true;
+    }
+
+  return false;
+}
+
+/* Examine the block associated with LP to determine if it's an empty
+   handler for its EH region.  If so, attempt to redirect EH edges to
+   an outer region.  Return true the CFG was updated in any way.  This
+   is similar to jump forwarding, just across EH edges.  */
+
+static bool
+cleanup_empty_eh (eh_landing_pad lp)
+{
+  basic_block bb = label_to_block (lp->post_landing_pad);
+  gimple_stmt_iterator gsi;
+  gimple resx;
+  eh_region new_region;
+  edge_iterator ei;
+  edge e, e_out;
+  bool has_non_eh_pred;
+  int new_lp_nr;
+
+  /* There can be zero or one edges out of BB.  This is the quickest test.  */
+  switch (EDGE_COUNT (bb->succs))
+    {
+    case 0:
+      e_out = NULL;
+      break;
+    case 1:
+      e_out = EDGE_SUCC (bb, 0);
+      break;
+    default:
+      return false;
+    }
+  gsi = gsi_after_labels (bb);
+
+  /* Make sure to skip debug statements.  */
+  if (!gsi_end_p (gsi) && is_gimple_debug (gsi_stmt (gsi)))
+    gsi_next_nondebug (&gsi);
+
+  /* If the block is totally empty, look for more unsplitting cases.  */
+  if (gsi_end_p (gsi))
+    return cleanup_empty_eh_unsplit (bb, e_out, lp);
+
+  /* The block should consist only of a single RESX statement.  */
+  resx = gsi_stmt (gsi);
+  if (!is_gimple_resx (resx))
+    return false;
+  gcc_assert (gsi_one_before_end_p (gsi));
+
+  /* Determine if there are non-EH edges, or resx edges into the handler.  */
+  has_non_eh_pred = false;
+  FOR_EACH_EDGE (e, ei, bb->preds)
+    if (!(e->flags & EDGE_EH))
+      has_non_eh_pred = true;
+
+  /* Find the handler that's outer of the empty handler by looking at
+     where the RESX instruction was vectored.  */
+  new_lp_nr = lookup_stmt_eh_lp (resx);
+  new_region = get_eh_region_from_lp_number (new_lp_nr);
+
+  /* If there's no destination region within the current function,
+     redirection is trivial via removing the throwing statements from
+     the EH region, removing the EH edges, and allowing the block
+     to go unreachable.  */
+  if (new_region == NULL)
+    {
+      gcc_assert (e_out == NULL);
+      for (ei = ei_start (bb->preds); (e = ei_safe_edge (ei)); )
+       if (e->flags & EDGE_EH)
+         {
+           gimple stmt = last_stmt (e->src);
+           remove_stmt_from_eh_lp (stmt);
+           remove_edge (e);
+         }
+       else
+         ei_next (&ei);
+      goto succeed;
+    }
+
+  /* If the destination region is a MUST_NOT_THROW, allow the runtime
+     to handle the abort and allow the blocks to go unreachable.  */
+  if (new_region->type == ERT_MUST_NOT_THROW)
+    {
+      for (ei = ei_start (bb->preds); (e = ei_safe_edge (ei)); )
+       if (e->flags & EDGE_EH)
+         {
+           gimple stmt = last_stmt (e->src);
+           remove_stmt_from_eh_lp (stmt);
+           add_stmt_to_eh_lp (stmt, new_lp_nr);
+           remove_edge (e);
+         }
+       else
+         ei_next (&ei);
+      goto succeed;
+    }
+
+  /* Try to redirect the EH edges and merge the PHIs into the destination
+     landing pad block.  If the merge succeeds, we'll already have redirected
+     all the EH edges.  The handler itself will go unreachable if there were
+     no normal edges.  */
+  if (cleanup_empty_eh_merge_phis (e_out->dest, bb, e_out))
+    goto succeed;
+
+  /* Finally, if all input edges are EH edges, then we can (potentially)
+     reduce the number of transfers from the runtime by moving the landing
+     pad from the original region to the new region.  This is a win when
+     we remove the last CLEANUP region along a particular exception
+     propagation path.  Since nothing changes except for the region with
+     which the landing pad is associated, the PHI nodes do not need to be
+     adjusted at all.  */
+  if (!has_non_eh_pred)
+    {
+      cleanup_empty_eh_move_lp (bb, e_out, lp, new_region);
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       fprintf (dump_file, "Empty EH handler %i moved to EH region %i.\n",
+                lp->index, new_region->index);
+
+      /* ??? The CFG didn't change, but we may have rendered the
+        old EH region unreachable.  Trigger a cleanup there.  */
       return true;
     }
+
   return false;
+
+ succeed:
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    fprintf (dump_file, "Empty EH handler %i removed.\n", lp->index);
+  remove_eh_landing_pad (lp);
+  return true;
 }
 
+/* Do a post-order traversal of the EH region tree.  Examine each
+   post_landing_pad block and see if we can eliminate it as empty.  */
+
+static bool
+cleanup_all_empty_eh (void)
+{
+  bool changed = false;
+  eh_landing_pad lp;
+  int i;
+
+  for (i = 1; VEC_iterate (eh_landing_pad, cfun->eh->lp_array, i, lp); ++i)
+    if (lp)
+      changed |= cleanup_empty_eh (lp);
+
+  return changed;
+}
 
 /* Perform cleanups and lowering of exception handling
     1) cleanups regions with handlers doing nothing are optimized out
@@ -3246,63 +3749,58 @@ cleanup_empty_eh (basic_block bb, VEC(int,heap) * label_to_region)
     3) Info about regions that are containing instructions, and regions
        reachable via local EH edges is collected
     4) Eh tree is pruned for regions no longer neccesary.
- */
+
+   TODO: Push MUST_NOT_THROW regions to the root of the EH tree.
+        Unify those that have the same failure decl and locus.
+*/
 
 static unsigned int
-cleanup_eh (void)
+execute_cleanup_eh (void)
 {
-  bool changed = false;
-  basic_block bb;
-  VEC(int,heap) * label_to_region;
-  int i;
+  /* Do this first: unsplit_all_eh and cleanup_all_empty_eh can die
+     looking up unreachable landing pads.  */
+  remove_unreachable_handlers ();
 
-  if (!cfun->eh)
-    return 0;
-  if (dump_file)
+  /* Watch out for the region tree vanishing due to all unreachable.  */
+  if (cfun->eh->region_tree && optimize)
     {
-      fprintf (dump_file, "Before cleanups:\n");
-      dump_eh_tree (dump_file, cfun);
-    }
+      bool changed = false;
 
-  if (optimize)
-    {
-      label_to_region = label_to_region_map ();
-      dominance_info_invalidated = false;
-      /* We cannot use FOR_EACH_BB, since the basic blocks may get removed.  */
-      for (i = NUM_FIXED_BLOCKS; i < last_basic_block; i++)
-       {
-         bb = BASIC_BLOCK (i);
-         if (bb)
-           changed |= cleanup_empty_eh (bb, label_to_region);
-       }
-      VEC_free (int, heap, label_to_region);
-      if (dominance_info_invalidated)
+      changed |= unsplit_all_eh ();
+      changed |= cleanup_all_empty_eh ();
+
+      if (changed)
        {
          free_dominance_info (CDI_DOMINATORS);
          free_dominance_info (CDI_POST_DOMINATORS);
-       }
 
-      /* Removing contained cleanup can render MUST_NOT_THROW regions empty.  */
-      if (changed)
-       delete_unreachable_blocks ();
-    }
+          /* We delayed all basic block deletion, as we may have performed
+            cleanups on EH edges while non-EH edges were still present.  */
+         delete_unreachable_blocks ();
 
-  tree_remove_unreachable_handlers ();
-  if (dump_file)
-    {
-      fprintf (dump_file, "After cleanups:\n");
-      dump_eh_tree (dump_file, cfun);
+         /* We manipulated the landing pads.  Remove any region that no
+            longer has a landing pad.  */
+         remove_unreachable_handlers_no_lp ();
+
+         return TODO_cleanup_cfg | TODO_update_ssa_only_virtuals;
+       }
     }
 
-  return (changed ? TODO_cleanup_cfg | TODO_update_ssa : 0);
+  return 0;
+}
+
+static bool
+gate_cleanup_eh (void)
+{
+  return cfun->eh != NULL && cfun->eh->region_tree != NULL;
 }
 
 struct gimple_opt_pass pass_cleanup_eh = {
   {
    GIMPLE_PASS,
    "ehcleanup",                        /* name */
-   NULL,                       /* gate */
-   cleanup_eh,                 /* execute */
+   gate_cleanup_eh,            /* gate */
+   execute_cleanup_eh,         /* execute */
    NULL,                       /* sub */
    NULL,                       /* next */
    0,                          /* static_pass_number */
@@ -3314,3 +3812,150 @@ struct gimple_opt_pass pass_cleanup_eh = {
    TODO_dump_func              /* todo_flags_finish */
    }
 };
+\f
+/* Verify that BB containing STMT as the last statement, has precisely the
+   edge that make_eh_edges would create.  */
+
+bool
+verify_eh_edges (gimple stmt)
+{
+  basic_block bb = gimple_bb (stmt);
+  eh_landing_pad lp = NULL;
+  int lp_nr;
+  edge_iterator ei;
+  edge e, eh_edge;
+
+  lp_nr = lookup_stmt_eh_lp (stmt);
+  if (lp_nr > 0)
+    lp = get_eh_landing_pad_from_number (lp_nr);
+
+  eh_edge = NULL;
+  FOR_EACH_EDGE (e, ei, bb->succs)
+    {
+      if (e->flags & EDGE_EH)
+       {
+         if (eh_edge)
+           {
+             error ("BB %i has multiple EH edges", bb->index);
+             return true;
+           }
+         else
+           eh_edge = e;
+       }
+    }
+
+  if (lp == NULL)
+    {
+      if (eh_edge)
+       {
+         error ("BB %i can not throw but has an EH edge", bb->index);
+         return true;
+       }
+      return false;
+    }
+
+  if (!stmt_could_throw_p (stmt))
+    {
+      error ("BB %i last statement has incorrectly set lp", bb->index);
+      return true;
+    }
+
+  if (eh_edge == NULL)
+    {
+      error ("BB %i is missing an EH edge", bb->index);
+      return true;
+    }
+
+  if (eh_edge->dest != label_to_block (lp->post_landing_pad))
+    {
+      error ("Incorrect EH edge %i->%i", bb->index, eh_edge->dest->index);
+      return true;
+    }
+
+  return false;
+}
+
+/* Similarly, but handle GIMPLE_EH_DISPATCH specifically.  */
+
+bool
+verify_eh_dispatch_edge (gimple stmt)
+{
+  eh_region r;
+  eh_catch c;
+  basic_block src, dst;
+  bool want_fallthru = true;
+  edge_iterator ei;
+  edge e, fall_edge;
+
+  r = get_eh_region_from_number (gimple_eh_dispatch_region (stmt));
+  src = gimple_bb (stmt);
+
+  FOR_EACH_EDGE (e, ei, src->succs)
+    gcc_assert (e->aux == NULL);
+
+  switch (r->type)
+    {
+    case ERT_TRY:
+      for (c = r->u.eh_try.first_catch; c ; c = c->next_catch)
+       {
+         dst = label_to_block (c->label);
+         e = find_edge (src, dst);
+         if (e == NULL)
+           {
+             error ("BB %i is missing an edge", src->index);
+             return true;
+           }
+         e->aux = (void *)e;
+
+         /* A catch-all handler doesn't have a fallthru.  */
+         if (c->type_list == NULL)
+           {
+             want_fallthru = false;
+             break;
+           }
+       }
+      break;
+
+    case ERT_ALLOWED_EXCEPTIONS:
+      dst = label_to_block (r->u.allowed.label);
+      e = find_edge (src, dst);
+      if (e == NULL)
+       {
+         error ("BB %i is missing an edge", src->index);
+         return true;
+       }
+      e->aux = (void *)e;
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  fall_edge = NULL;
+  FOR_EACH_EDGE (e, ei, src->succs)
+    {
+      if (e->flags & EDGE_FALLTHRU)
+       {
+         if (fall_edge != NULL)
+           {
+             error ("BB %i too many fallthru edges", src->index);
+             return true;
+           }
+         fall_edge = e;
+       }
+      else if (e->aux)
+       e->aux = NULL;
+      else
+       {
+         error ("BB %i has incorrect edge", src->index);
+         return true;
+       }
+    }
+  if ((fall_edge != NULL) ^ want_fallthru)
+    {
+      error ("BB %i has incorrect fallthru edge", src->index);
+      return true;
+    }
+
+  return false;
+}
index 9af6cbd4e32296482b1d73e466d2eacb426d808a..b93e2f4a373e86a891eb458c52071e4118de5f22 100644 (file)
@@ -134,9 +134,9 @@ struct GTY(()) tree_ann_common_d {
   /* Annotation type.  */
   enum tree_ann_type type;
 
-  /* Record EH region number into a statement tree created during RTL
-     expansion (see gimple_to_tree).  */
-  int rn;
+  /* Record EH landing pad number into a statement tree created
+     during RTL expansion (see gimple_to_tree).  */
+  int lp_nr;
 
   /* Pointer to original GIMPLE statement.  Used during RTL expansion
      (see gimple_to_tree).  */
@@ -807,6 +807,9 @@ bool contains_abnormal_ssa_name_p (tree);
 bool stmt_dominates_stmt_p (gimple, gimple);
 void mark_virtual_ops_for_renaming (gimple);
 
+/* In tree-ssa-dce.c */
+void mark_virtual_phi_result_for_renaming (gimple);
+
 /* In tree-ssa-threadedge.c */
 extern void threadedge_initialize_values (void);
 extern void threadedge_finalize_values (void);
@@ -842,6 +845,9 @@ static inline bool array_ref_contains_indirect_ref (const_tree);
 
 /* In tree-eh.c  */
 extern void make_eh_edges (gimple);
+extern bool make_eh_dispatch_edges (gimple);
+extern edge redirect_eh_edge (edge, basic_block);
+extern void redirect_eh_dispatch_edge (gimple, edge, basic_block);
 extern bool tree_could_trap_p (tree);
 extern bool operation_could_trap_helper_p (enum tree_code, bool, bool, bool,
                                           bool, tree, bool *);
@@ -850,16 +856,22 @@ extern bool stmt_could_throw_p (gimple);
 extern bool tree_could_throw_p (tree);
 extern bool stmt_can_throw_internal (gimple);
 extern bool stmt_can_throw_external (gimple);
-extern void add_stmt_to_eh_region (gimple, int);
-extern bool remove_stmt_from_eh_region (gimple);
+extern void add_stmt_to_eh_lp_fn (struct function *, gimple, int);
+extern void add_stmt_to_eh_lp (gimple, int);
+extern bool remove_stmt_from_eh_lp (gimple);
+extern bool remove_stmt_from_eh_lp_fn (struct function *, gimple);
+extern int lookup_stmt_eh_lp_fn (struct function *, gimple);
+extern int lookup_expr_eh_lp (tree);
+extern int lookup_stmt_eh_lp (gimple);
+extern bool maybe_clean_eh_stmt_fn (struct function *, gimple);
+extern bool maybe_clean_eh_stmt (gimple);
 extern bool maybe_clean_or_replace_eh_stmt (gimple, gimple);
-extern void add_stmt_to_eh_region_fn (struct function *, gimple, int);
-extern bool remove_stmt_from_eh_region_fn (struct function *, gimple);
-extern int lookup_stmt_eh_region_fn (struct function *, gimple);
-extern int lookup_expr_eh_region (tree);
-extern int lookup_stmt_eh_region (gimple);
+extern bool maybe_duplicate_eh_stmt_fn (struct function *, gimple,
+                                       struct function *, gimple,
+                                       struct pointer_map_t *, int);
+extern bool maybe_duplicate_eh_stmt (gimple, gimple);
 extern bool verify_eh_edges (gimple);
-
+extern bool verify_eh_dispatch_edge (gimple);
 
 /* In tree-ssa-pre.c  */
 struct pre_expr_d;
@@ -926,6 +938,5 @@ unsigned int execute_fixup_cfg (void);
 void swap_tree_operands (gimple, tree *, tree *);
 
 int least_common_multiple (int, int);
-edge redirect_eh_edge (edge e, basic_block new_bb);
 
 #endif /* _TREE_FLOW_H  */
index b83c52f537017dfb130078e0a33c6c8998104a11..5ada378700fb05ab4c06b74c169bff760824e344 100644 (file)
@@ -64,7 +64,7 @@ along with GCC; see the file COPYING3.  If not see
    MODIFY_EXPRs that store to a dedicated returned-value variable.
    The duplicated eh_region info of the copy will later be appended
    to the info for the caller; the eh_region info in copied throwing
-   statements and RESX_EXPRs is adjusted accordingly.
+   statements and RESX statements are adjusted accordingly.
 
    Cloning: (only in C++) We have one body for a con/de/structor, and
    multiple function decls, each with a unique parameter list.
@@ -1105,12 +1105,6 @@ copy_tree_body_r (tree *tp, int *walk_subtrees, void *data)
          TREE_BLOCK (*tp) = new_block;
        }
 
-      if (TREE_CODE (*tp) == RESX_EXPR && id->eh_region_offset)
-       TREE_OPERAND (*tp, 0) =
-         build_int_cst (NULL_TREE,
-                        id->eh_region_offset
-                        + TREE_INT_CST_LOW (TREE_OPERAND (*tp, 0)));
-
       if (TREE_CODE (*tp) != OMP_CLAUSE)
        TREE_TYPE (*tp) = remap_type (TREE_TYPE (*tp), id);
 
@@ -1150,6 +1144,35 @@ copy_tree_body_r (tree *tp, int *walk_subtrees, void *data)
   return NULL_TREE;
 }
 
+/* Helper for remap_gimple_stmt.  Given an EH region number for the
+   source function, map that to the duplicate EH region number in
+   the destination function.  */
+
+static int
+remap_eh_region_nr (int old_nr, copy_body_data *id)
+{
+  eh_region old_r, new_r;
+  void **slot;
+
+  old_r = get_eh_region_from_number_fn (id->src_cfun, old_nr);
+  slot = pointer_map_contains (id->eh_map, old_r);
+  new_r = (eh_region) *slot;
+
+  return new_r->index;
+}
+
+/* Similar, but operate on INTEGER_CSTs.  */
+
+static tree
+remap_eh_region_tree_nr (tree old_t_nr, copy_body_data *id)
+{
+  int old_nr, new_nr;
+
+  old_nr = tree_low_cst (old_t_nr, 0);
+  new_nr = remap_eh_region_nr (old_nr, id);
+
+  return build_int_cst (NULL, new_nr);
+}
 
 /* Helper for copy_bb.  Remap statement STMT using the inlining
    information in ID.  Return the new statement copy.  */
@@ -1339,9 +1362,59 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id)
          VEC_safe_push (gimple, heap, id->debug_stmts, copy);
          return copy;
        }
-      else
-       /* Create a new deep copy of the statement.  */
-       copy = gimple_copy (stmt);
+
+      /* Create a new deep copy of the statement.  */
+      copy = gimple_copy (stmt);
+
+      /* Remap the region numbers for __builtin_eh_{pointer,filter},
+        RESX and EH_DISPATCH.  */
+      if (id->eh_map)
+       switch (gimple_code (copy))
+         {
+         case GIMPLE_CALL:
+           {
+             tree r, fndecl = gimple_call_fndecl (copy);
+             if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
+               switch (DECL_FUNCTION_CODE (fndecl))
+                 {
+                 case BUILT_IN_EH_COPY_VALUES:
+                   r = gimple_call_arg (copy, 1);
+                   r = remap_eh_region_tree_nr (r, id);
+                   gimple_call_set_arg (copy, 1, r);
+                   /* FALLTHRU */
+
+                 case BUILT_IN_EH_POINTER:
+                 case BUILT_IN_EH_FILTER:
+                   r = gimple_call_arg (copy, 0);
+                   r = remap_eh_region_tree_nr (r, id);
+                   gimple_call_set_arg (copy, 0, r);
+                   break;
+
+                 default:
+                   break;
+                 }
+           }
+           break;
+
+         case GIMPLE_RESX:
+           {
+             int r = gimple_resx_region (copy);
+             r = remap_eh_region_nr (r, id);
+             gimple_resx_set_region (copy, r);
+           }
+           break;
+
+         case GIMPLE_EH_DISPATCH:
+           {
+             int r = gimple_eh_dispatch_region (copy);
+             r = remap_eh_region_nr (r, id);
+             gimple_eh_dispatch_set_region (copy, r);
+           }
+           break;
+
+         default:
+           break;
+         }
     }
 
   /* If STMT has a block defined, map it to the newly constructed
@@ -1377,12 +1450,6 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id)
       gimple_set_vuse (copy, NULL_TREE);
     }
 
-  /* We have to handle EH region remapping of GIMPLE_RESX specially because
-     the region number is not an operand.  */
-  if (gimple_code (stmt) == GIMPLE_RESX && id->eh_region_offset)
-    {
-      gimple_resx_set_region (copy, gimple_resx_region (stmt) + id->eh_region_offset);
-    }
   return copy;
 }
 
@@ -1617,43 +1684,8 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
                cfun->calls_setjmp = true;
            }
 
-         /* If you think we can abort here, you are wrong.
-            There is no region 0 in gimple.  */
-         gcc_assert (lookup_stmt_eh_region_fn (id->src_cfun, orig_stmt) != 0);
-
-         if (stmt_could_throw_p (stmt)
-             /* When we are cloning for inlining, we are supposed to
-                construct a clone that calls precisely the same functions
-                as original.  However IPA optimizers might've proved
-                earlier some function calls as non-trapping that might
-                render some basic blocks dead that might become
-                unreachable.
-
-                We can't update SSA with unreachable blocks in CFG and thus
-                we prevent the scenario by preserving even the "dead" eh
-                edges until the point they are later removed by
-                fixup_cfg pass.  */
-             || (id->transform_call_graph_edges == CB_CGE_MOVE_CLONES
-                 && lookup_stmt_eh_region_fn (id->src_cfun, orig_stmt) > 0))
-           {
-             int region = lookup_stmt_eh_region_fn (id->src_cfun, orig_stmt);
-
-             /* Add an entry for the copied tree in the EH hashtable.
-                When cloning or versioning, use the hashtable in
-                cfun, and just copy the EH number.  When inlining, use the
-                hashtable in the caller, and adjust the region number.  */
-             if (region > 0)
-               add_stmt_to_eh_region (stmt, region + id->eh_region_offset);
-
-             /* If this tree doesn't have a region associated with it,
-                and there is a "current region,"
-                then associate this tree with the current region
-                and add edges associated with this region.  */
-             if (lookup_stmt_eh_region_fn (id->src_cfun, orig_stmt) <= 0
-                 && id->eh_region > 0
-                 && stmt_could_throw_p (stmt))
-               add_stmt_to_eh_region (stmt, id->eh_region);
-           }
+         maybe_duplicate_eh_stmt_fn (cfun, stmt, id->src_cfun, orig_stmt,
+                                     id->eh_map, id->eh_lp_nr);
 
          if (gimple_in_ssa_p (cfun) && !is_gimple_debug (stmt))
            {
@@ -1822,7 +1854,9 @@ copy_edges_for_bb (basic_block bb, gcov_type count_scale, basic_block ret_bb)
            }
        }
 
-      if (can_throw)
+      if (gimple_code (copy_stmt) == GIMPLE_EH_DISPATCH)
+       make_eh_dispatch_edges (copy_stmt);
+      else if (can_throw)
        make_eh_edges (copy_stmt);
 
       if (nonlocal_goto)
@@ -2025,11 +2059,8 @@ copy_cfg_body (copy_body_data * id, gcov_type count, int frequency,
 
   /* Duplicate any exception-handling regions.  */
   if (cfun->eh)
-    {
-      id->eh_region_offset
-       = duplicate_eh_regions (cfun_to_copy, remap_decl_1, id,
-                               0, id->eh_region);
-    }
+    id->eh_map = duplicate_eh_regions (cfun_to_copy, NULL, id->eh_lp_nr,
+                                      remap_decl_1, id);
 
   /* Use aux pointers to map the original blocks to copy.  */
   FOR_EACH_BB_FN (bb, cfun_to_copy)
@@ -2062,6 +2093,12 @@ copy_cfg_body (copy_body_data * id, gcov_type count, int frequency,
   entry_block_map->aux = NULL;
   exit_block_map->aux = NULL;
 
+  if (id->eh_map)
+    {
+      pointer_map_destroy (id->eh_map);
+      id->eh_map = NULL;
+    }
+
   return new_fndecl;
 }
 
@@ -3190,14 +3227,6 @@ estimate_num_insns (gimple stmt, eni_weights *weights)
       lhs = gimple_assign_lhs (stmt);
       rhs = gimple_assign_rhs1 (stmt);
 
-      /* EH magic stuff is most probably going to be optimized out.
-         We rarely really need to save EH info for unwinding
-         nested exceptions.  */
-      if (TREE_CODE (lhs) == FILTER_EXPR
-         || TREE_CODE (lhs) == EXC_PTR_EXPR
-          || TREE_CODE (rhs) == FILTER_EXPR
-         || TREE_CODE (rhs) == EXC_PTR_EXPR)
-       return 0;
       if (is_gimple_reg (lhs))
        cost = 0;
       else
@@ -3308,9 +3337,19 @@ estimate_num_insns (gimple stmt, eni_weights *weights)
       return 0;
 
     case GIMPLE_ASM:
-    case GIMPLE_RESX:
       return 1;
 
+    case GIMPLE_RESX:
+      /* This is either going to be an external function call with one
+        argument, or two register copy statements plus a goto.  */
+      return 2;
+
+    case GIMPLE_EH_DISPATCH:
+      /* ??? This is going to turn into a switch statement.  Ideally
+        we'd have a look at the eh region and estimate the number of
+        edges involved.  */
+      return 10;
+
     case GIMPLE_BIND:
       return estimate_num_insns_seq (gimple_bind_body (stmt), weights);
 
@@ -3551,7 +3590,7 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
 #endif
 
   /* We will be inlining this callee.  */
-  id->eh_region = lookup_stmt_eh_region (stmt);
+  id->eh_lp_nr = lookup_stmt_eh_lp (stmt);
 
   /* Update the callers EH personality.  */
   if (DECL_FUNCTION_PERSONALITY (cg_edge->callee->decl))
@@ -4935,7 +4974,7 @@ maybe_inline_call_in_expr (tree exp)
       id.do_not_unshare = true;
 
       /* We're not inside any EH region.  */
-      id.eh_region = -1;
+      id.eh_lp_nr = 0;
 
       t = copy_tree_body (&id);
       pointer_map_destroy (decl_map);
index f04a3f0a8437b2ecad9e9c9f61ef99c71e565bc5..29932e84e38aa11b06e0b8d0b6b8a8cf88ad054f 100644 (file)
@@ -77,12 +77,12 @@ typedef struct copy_body_data
      is not.  */
   gimple gimple_call;
 
-  /* Exception region the inlined call lie in.  */
-  int eh_region;
+  /* Exception landing pad the inlined call lies in.  */
+  int eh_lp_nr;
 
-  /* Take region number in the function being copied, add this value and
-     get eh region number of the duplicate in the function we inline into.  */
-  int eh_region_offset;
+  /* Maps region and landing pad structures from the function being copied
+     to duplicates created within the function we inline into.  */
+  struct pointer_map_t *eh_map;
 
   /* We use the same mechanism do all sorts of different things.  Rather
      than enumerating the different cases, we categorize the behavior
index 7a9d2bd7c46902ee6101e50789dad3d7fbeca601..73eacf6c2f2bebe62c1426cd3963aaff697b531c 100644 (file)
@@ -269,8 +269,7 @@ execute_fixup_cfg (void)
                  }
              }
 
-           if (!stmt_could_throw_p (stmt) && lookup_stmt_eh_region (stmt))
-             remove_stmt_from_eh_region (stmt);
+           maybe_clean_eh_stmt (stmt);
          }
 
        if (gimple_purge_dead_eh_edges (bb))
index 4bb3364039ee9ab3dcb59adf092d9850bf35d4ba..9ea70e35fb7e2906ae4e02508c665fff90f16266 100644 (file)
@@ -316,6 +316,8 @@ extern struct gimple_opt_pass pass_remove_useless_stmts;
 extern struct gimple_opt_pass pass_lower_cf;
 extern struct gimple_opt_pass pass_refactor_eh;
 extern struct gimple_opt_pass pass_lower_eh;
+extern struct gimple_opt_pass pass_lower_eh_dispatch;
+extern struct gimple_opt_pass pass_lower_resx;
 extern struct gimple_opt_pass pass_build_cfg;
 extern struct gimple_opt_pass pass_tree_profile;
 extern struct gimple_opt_pass pass_early_tree_profile;
index 2c64ab96aa0a7a66133cdd8e2e815f4b660c84e1..a325d75d91442cfba71c783c7d506dd2aa6cce05 100644 (file)
@@ -1687,14 +1687,6 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
        pp_string (buffer, " [non-local]");
       break;
 
-    case EXC_PTR_EXPR:
-      pp_string (buffer, "<<<exception object>>>");
-      break;
-
-    case FILTER_EXPR:
-      pp_string (buffer, "<<<filter object>>>");
-      break;
-
     case LOOP_EXPR:
       pp_string (buffer, "while (1)");
       if (!(flags & TDF_SLIM))
@@ -1795,11 +1787,6 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
       dump_generic_node (buffer, op0, spc, flags, false);
       break;
 
-    case RESX_EXPR:
-      pp_string (buffer, "resx ");
-      dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
-      break;
-
     case ASM_EXPR:
       pp_string (buffer, "__asm__");
       if (ASM_VOLATILE_P (node))
index 1a0622ef8eb824eb2fb781a31ef5fefad7be5d38..00686c8a2190a6731276f883913be1150f3fefbc 100644 (file)
@@ -890,8 +890,7 @@ scan_function (bool (*scan_expr) (tree *, gimple_stmt_iterator *, bool, void *),
              if (!analysis_stage)
                {
                  update_stmt (stmt);
-                 if (!stmt_could_throw_p (stmt))
-                   remove_stmt_from_eh_region (stmt);
+                 maybe_clean_eh_stmt (stmt);
                }
            }
          if (deleted)
index 89804a923b19acdbd3afc9d08bb35bbaaa6e68b3..9522b28c5484cb5b8caa717f205033759bcae8b7 100644 (file)
@@ -1028,10 +1028,6 @@ process_args:
     {
       tree op = gimple_call_arg (call, i);
 
-      if (TREE_CODE (op) == EXC_PTR_EXPR
-         || TREE_CODE (op) == FILTER_EXPR)
-       continue;
-
       if (TREE_CODE (op) == WITH_SIZE_EXPR)
        op = TREE_OPERAND (op, 0);
 
index 99a039fffee59fbf08afcb3d8c25adcbba428ae8..67d0472cc59668c603900702bc87d06b1dfd2b8c 100644 (file)
@@ -322,15 +322,6 @@ mark_stmt_if_obviously_necessary (gimple stmt, bool aggressive)
     case GIMPLE_ASSIGN:
       if (!lhs)
         lhs = gimple_assign_lhs (stmt);
-      /* These values are mildly magic bits of the EH runtime.  We can't
-        see the entire lifetime of these values until landing pads are
-        generated.  */
-      if (TREE_CODE (lhs) == EXC_PTR_EXPR
-         || TREE_CODE (lhs) == FILTER_EXPR)
-       {
-         mark_stmt_necessary (stmt, true);
-         return;
-       }
       break;
 
     case GIMPLE_DEBUG:
@@ -817,28 +808,33 @@ propagate_necessity (struct edge_list *el)
 /* Replace all uses of result of PHI by underlying variable and mark it
    for renaming.  */
 
-static void
+void
 mark_virtual_phi_result_for_renaming (gimple phi)
 {
   bool used = false;
   imm_use_iterator iter;
   use_operand_p use_p;
   gimple stmt;
+  tree result_ssa, result_var;
+
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
       fprintf (dump_file, "Marking result for renaming : ");
       print_gimple_stmt (dump_file, phi, 0, TDF_SLIM);
       fprintf (dump_file, "\n");
     }
-  FOR_EACH_IMM_USE_STMT (stmt, iter, gimple_phi_result (phi))
+
+  result_ssa = gimple_phi_result (phi);
+  result_var = SSA_NAME_VAR (result_ssa);
+  FOR_EACH_IMM_USE_STMT (stmt, iter, result_ssa)
     {
       FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
-        SET_USE (use_p, SSA_NAME_VAR (gimple_phi_result (phi)));
+        SET_USE (use_p, result_var);
       update_stmt (stmt);
       used = true;
     }
   if (used)
-    mark_sym_for_renaming (SSA_NAME_VAR (PHI_RESULT (phi)));
+    mark_sym_for_renaming (result_var);
 }
 
 /* Remove dead PHI nodes from block BB.  */
index 16f4a43dba32178067743d6c5c6036a7ca67af51..28e6ec65826f164edfd203932fd270f559391e2a 100644 (file)
@@ -1000,8 +1000,6 @@ get_expr_operands (gimple stmt, tree *expr_p, int flags)
     case LABEL_DECL:
     case CONST_DECL:
     case CASE_LABEL_EXPR:
-    case FILTER_EXPR:
-    case EXC_PTR_EXPR:
       /* Expressions that make no memory references.  */
       return;
 
index 267aeb5e2fde48c852b69b0fb05288a378bc08ee..5da6c63b4003e6a3465295433688138f5ad3cb58 100644 (file)
@@ -1068,9 +1068,7 @@ get_or_alloc_expr_for (tree t)
 {
   if (TREE_CODE (t) == SSA_NAME)
     return get_or_alloc_expr_for_name (t);
-  else if (is_gimple_min_invariant (t)
-          || TREE_CODE (t) == EXC_PTR_EXPR
-          || TREE_CODE (t) == FILTER_EXPR)
+  else if (is_gimple_min_invariant (t))
     return get_or_alloc_expr_for_constant (t);
   else
     {
@@ -2549,17 +2547,6 @@ can_value_number_call (gimple stmt)
   return false;
 }
 
-/* Return true if OP is an exception handler related operation, such as
-   FILTER_EXPR or EXC_PTR_EXPR.  */
-
-static bool
-is_exception_related (gimple stmt)
-{
-  return (is_gimple_assign (stmt)
-         && (gimple_assign_rhs_code (stmt) == FILTER_EXPR
-             || gimple_assign_rhs_code (stmt) == EXC_PTR_EXPR));
-}
-
 /* Return true if OP is a tree which we can perform PRE on.
    This may not match the operations we can value number, but in
    a perfect world would.  */
@@ -3885,8 +3872,6 @@ compute_avail (void)
                switch (TREE_CODE_CLASS (gimple_assign_rhs_code (stmt)))
                  {
                  case tcc_unary:
-                   if (is_exception_related (stmt))
-                     continue;
                  case tcc_binary:
                  case tcc_comparison:
                    {
index ab9cee34a218d37059210081b7618f11e7820cb4..42d89e919202fd8d1a23eaef65428dfec72f12d5 100644 (file)
@@ -617,10 +617,6 @@ valid_gimple_rhs_p (tree expr)
            return false;
          break;
 
-       case EXC_PTR_EXPR:
-       case FILTER_EXPR:
-         break;
-
        default:
          return false;
        }
index 255e8a533b87a165dbafa9aaa0575b0fc859ab33..4158fbd88dfa44cbd6bf4a5e09cfdb4107cfc753 100644 (file)
@@ -576,8 +576,6 @@ copy_reference_ops_from_ref (tree ref, VEC(vn_reference_op_s, heap) **result)
        case CONST_DECL:
        case RESULT_DECL:
        case SSA_NAME:
-       case EXC_PTR_EXPR:
-       case FILTER_EXPR:
          temp.op0 = ref;
          break;
        case ADDR_EXPR:
@@ -688,8 +686,6 @@ ao_ref_init_from_vn_reference (ao_ref *ref,
        case PARM_DECL:
        case RESULT_DECL:
        case SSA_NAME:
-       case FILTER_EXPR:
-       case EXC_PTR_EXPR:
          *op0_p = op->op0;
          break;
 
index 5b9b4be3090d1dad881c1f5831ae86dc25f8afb8..a9b4b67679b431fb29aef36c56fb8b036527d2df 100644 (file)
@@ -323,8 +323,6 @@ statement_sink_location (gimple stmt, basic_block frombb,
   code = gimple_assign_rhs_code (stmt);
   if (stmt_ends_bb_p (stmt)
       || gimple_has_side_effects (stmt)
-      || code == EXC_PTR_EXPR
-      || code == FILTER_EXPR
       || is_hidden_global_store (stmt)
       || gimple_has_volatile_ops (stmt)
       || gimple_vuse (stmt)
index a9d31325b5746fb97547f08b3a49a59217e1bc55..e5f4a292855ae521af8e0ac2eeb0a482ad870650 100644 (file)
@@ -425,10 +425,6 @@ struct constraint
 static VEC(constraint_t,heap) *constraints;
 static alloc_pool constraint_pool;
 
-
-DEF_VEC_I(int);
-DEF_VEC_ALLOC_I(int, heap);
-
 /* The constraint graph is represented as an array of bitmaps
    containing successor nodes.  */
 
@@ -1287,10 +1283,6 @@ build_succ_graph (void)
 static unsigned int changed_count;
 static sbitmap changed;
 
-DEF_VEC_I(unsigned);
-DEF_VEC_ALLOC_I(unsigned,heap);
-
-
 /* Strongly Connected Component visitation info.  */
 
 struct scc_info
index 98a683dea9d4432c590dd81d7a5c21cf3d74df15..d2243e5d1bd474444084e38bfd7f4d7e4d197725 100644 (file)
@@ -4667,23 +4667,36 @@ get_eh_types_for_runtime (tree list)
 static void
 find_decls_types_in_eh_region (eh_region r, struct free_lang_data_d *fld)
 {
-  if (r == NULL)
-    return;
-
-  /* The types referenced in R must first be changed to the EH types
-     used at runtime.  This removes references to FE types in the
-     region.  */
-  if (r->type == ERT_CATCH)
+  switch (r->type)
     {
-      tree list = r->u.eh_catch.type_list;
-      r->u.eh_catch.type_list = get_eh_types_for_runtime (list);
-      find_decls_types (r->u.eh_catch.type_list, fld);
-    }
-  else if (r->type == ERT_ALLOWED_EXCEPTIONS)
-    {
-      tree list = r->u.allowed.type_list;
-      r->u.allowed.type_list = get_eh_types_for_runtime (list);
-      find_decls_types (r->u.allowed.type_list, fld);
+    case ERT_CLEANUP:
+      break;
+
+    case ERT_TRY:
+      {
+       eh_catch c;
+
+       /* The types referenced in each catch must first be changed to the
+          EH types used at runtime.  This removes references to FE types
+          in the region.  */
+       for (c = r->u.eh_try.first_catch; c ; c = c->next_catch)
+         {
+           c->type_list = get_eh_types_for_runtime (c->type_list);
+           walk_tree (&c->type_list, find_decls_types_r, fld, fld->pset);
+         }
+      }
+      break;
+
+    case ERT_ALLOWED_EXCEPTIONS:
+      r->u.allowed.type_list
+       = get_eh_types_for_runtime (r->u.allowed.type_list);
+      walk_tree (&r->u.allowed.type_list, find_decls_types_r, fld, fld->pset);
+      break;
+
+    case ERT_MUST_NOT_THROW:
+      walk_tree (&r->u.must_not_throw.failure_decl,
+                find_decls_types_r, fld, fld->pset);
+      break;
     }
 }
 
@@ -4715,14 +4728,11 @@ find_decls_types_in_node (struct cgraph_node *n, struct free_lang_data_d *fld)
     find_decls_types (TREE_VALUE (t), fld);
 
   /* Traverse EH regions in FN.  */
-  if (fn->eh->region_array)
-    {
-      unsigned i;
-      eh_region r;
-
-      for (i = 0; VEC_iterate (eh_region, fn->eh->region_array, i, r); i++)
-       find_decls_types_in_eh_region (r, fld);
-    }
+  {
+    eh_region r;
+    FOR_ALL_EH_REGION_FN (r, fn)
+      find_decls_types_in_eh_region (r, fld);
+  }
 
   /* Traverse every statement in FN.  */
   FOR_EACH_BB_FN (bb, fn)
@@ -8880,12 +8890,15 @@ local_define_builtin (const char *name, tree type, enum built_in_function code,
 
 /* Call this function after instantiating all builtins that the language
    front end cares about.  This will build the rest of the builtins that
-   are relied upon by the tree optimizers and the middle-end.  */
+   are relied upon by the tree optimizers and the middle-end.
+
+   ENABLE_CXA_END_CLEANUP should be true for C++ and Java, where the ARM
+   EABI requires a slightly different implementation of _Unwind_Resume.  */
 
 void
-build_common_builtin_nodes (void)
+build_common_builtin_nodes (bool enable_cxa_end_cleanup)
 {
-  tree tmp, ftype;
+  tree tmp, tmp2, ftype;
 
   if (built_in_decls[BUILT_IN_MEMCPY] == NULL
       || built_in_decls[BUILT_IN_MEMMOVE] == NULL)
@@ -8990,6 +9003,47 @@ build_common_builtin_nodes (void)
   local_define_builtin ("__builtin_profile_func_exit", ftype,
                        BUILT_IN_PROFILE_FUNC_EXIT, "profile_func_exit", 0);
 
+  if (enable_cxa_end_cleanup && targetm.arm_eabi_unwinder)
+    {
+      ftype = build_function_type (void_type_node, void_list_node);
+      local_define_builtin ("__builtin_unwind_resume", ftype,
+                           BUILT_IN_UNWIND_RESUME,
+                           "__cxa_end_cleanup", ECF_NORETURN);
+    }
+  else
+    {
+      tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
+      ftype = build_function_type (void_type_node, tmp);
+      local_define_builtin ("__builtin_unwind_resume", ftype,
+                           BUILT_IN_UNWIND_RESUME,
+                           (USING_SJLJ_EXCEPTIONS
+                            ? "_Unwind_SjLj_Resume" : "_Unwind_Resume"),
+                           ECF_NORETURN);
+    }
+
+  /* The exception object and filter values from the runtime.  The argument
+     must be zero before exception lowering, i.e. from the front end.  After
+     exception lowering, it will be the region number for the exception
+     landing pad.  These functions are PURE instead of CONST to prevent
+     them from being hoisted past the exception edge that will initialize
+     its value in the landing pad.  */
+  tmp = tree_cons (NULL_TREE, integer_type_node, void_list_node);
+  ftype = build_function_type (ptr_type_node, tmp);
+  local_define_builtin ("__builtin_eh_pointer", ftype, BUILT_IN_EH_POINTER,
+                       "__builtin_eh_pointer", ECF_PURE | ECF_NOTHROW);
+
+  tmp2 = lang_hooks.types.type_for_mode (targetm.eh_return_filter_mode (), 0);
+  ftype = build_function_type (tmp2, tmp);
+  local_define_builtin ("__builtin_eh_filter", ftype, BUILT_IN_EH_FILTER,
+                       "__builtin_eh_filter", ECF_PURE | ECF_NOTHROW);
+
+  tmp = tree_cons (NULL_TREE, integer_type_node, void_list_node);
+  tmp = tree_cons (NULL_TREE, integer_type_node, tmp);
+  ftype = build_function_type (void_type_node, tmp);
+  local_define_builtin ("__builtin_eh_copy_values", ftype,
+                       BUILT_IN_EH_COPY_VALUES,
+                       "__builtin_eh_copy_values", ECF_NOTHROW);
+
   /* Complex multiplication and division.  These are handled as builtins
      rather than optabs because emit_library_call_value doesn't support
      complex.  Further, we can do slightly better with folding these 
@@ -9151,16 +9205,6 @@ build_opaque_vector_type (tree innertype, int nunits)
 }
 
 
-/* Build RESX_EXPR with given REGION_NUMBER.  */
-tree
-build_resx (int region_number)
-{
-  tree t;
-  t = build1 (RESX_EXPR, void_type_node,
-             build_int_cst (NULL_TREE, region_number));
-  return t;
-}
-
 /* Given an initializer INIT, return TRUE if INIT is zero or some
    aggregate of zeros.  Otherwise return FALSE.  */
 bool
index e7be1d0abab0aa82a4f3ef5b0bd0b8c2bff259d9..71987ef1d4d9b5e43ce5b424478fa67c9664041f 100644 (file)
@@ -440,12 +440,6 @@ DEFTREECODE (MISALIGNED_INDIRECT_REF, "misaligned_indirect_ref", tcc_reference,
    identifier or a vtable index.  */
 DEFTREECODE (OBJ_TYPE_REF, "obj_type_ref", tcc_expression, 3)
 
-/* The exception object from the runtime.  */
-DEFTREECODE (EXC_PTR_EXPR, "exc_ptr_expr", tcc_expression, 0)
-
-/* The filter object from the runtime.  */
-DEFTREECODE (FILTER_EXPR, "filter_expr", tcc_expression, 0)
-
 /* Constructor: return an aggregate value made from specified components.
    In C, this is used only for structure and array initializers.
    The operand is a sequence of component values made out of a VEC of
@@ -878,10 +872,6 @@ DEFTREECODE (SWITCH_EXPR, "switch_expr", tcc_statement, 3)
    label.  CASE_LABEL is the corresponding LABEL_DECL.  */
 DEFTREECODE (CASE_LABEL_EXPR, "case_label_expr", tcc_statement, 3)
 
-/* RESX.  Resume execution after an exception.  Operand 0 is a
-   number indicating the exception region that is being left.  */
-DEFTREECODE (RESX_EXPR, "resx_expr", tcc_statement, 1)
-
 /* Used to represent an inline assembly statement.  ASM_STRING returns a
    STRING_CST for the instruction (e.g., "mov x, y"). ASM_OUTPUTS,
    ASM_INPUTS, and ASM_CLOBBERS represent the outputs, inputs, and clobbers
index 5884b55a0b6dde5c78cdaa623cca28e6c9715a27..b9404c7da1889d5fd72737dfa82a8fef833f1218 100644 (file)
@@ -444,9 +444,6 @@ struct GTY(()) tree_common {
        ASM_INPUT_P in
            ASM_EXPR
 
-       EH_FILTER_MUST_NOT_THROW in
-           EH_FILTER_EXPR
-
        TYPE_REF_CAN_ALIAS_ALL in
            POINTER_TYPE, REFERENCE_TYPE
 
@@ -1659,8 +1656,6 @@ extern void protected_set_expr_location (tree, location_t);
 /* EH_FILTER_EXPR accessors.  */
 #define EH_FILTER_TYPES(NODE)  TREE_OPERAND (EH_FILTER_EXPR_CHECK (NODE), 0)
 #define EH_FILTER_FAILURE(NODE)        TREE_OPERAND (EH_FILTER_EXPR_CHECK (NODE), 1)
-#define EH_FILTER_MUST_NOT_THROW(NODE) \
-  (EH_FILTER_EXPR_CHECK (NODE)->base.static_flag)
 
 /* OBJ_TYPE_REF accessors.  */
 #define OBJ_TYPE_REF_EXPR(NODE)          TREE_OPERAND (OBJ_TYPE_REF_CHECK (NODE), 0)
@@ -2796,6 +2791,11 @@ struct GTY(()) tree_field_decl {
 #define LABEL_DECL_UID(NODE) \
   (LABEL_DECL_CHECK (NODE)->label_decl.label_decl_uid)
 
+/* In a LABEL_DECL, the EH region number for which the label is the
+   post_landing_pad.  */
+#define EH_LANDING_PAD_NR(NODE) \
+  (LABEL_DECL_CHECK (NODE)->label_decl.eh_landing_pad_nr)
+
 /* In LABEL_DECL nodes, nonzero means that an error message about
    jumping into such a binding contour has been printed for this label.  */
 #define DECL_ERROR_ISSUED(NODE) \
@@ -2804,6 +2804,7 @@ struct GTY(()) tree_field_decl {
 struct GTY(()) tree_label_decl {
   struct tree_decl_with_rtl common;
   int label_decl_uid;
+  int eh_landing_pad_nr;
 };
 
 struct GTY(()) tree_result_decl {
@@ -3914,7 +3915,6 @@ extern tree build_method_type_directly (tree, tree, tree);
 extern tree build_method_type (tree, tree);
 extern tree build_offset_type (tree, tree);
 extern tree build_complex_type (tree);
-extern tree build_resx (int);
 extern tree array_type_nelts (const_tree);
 extern bool in_array_bounds_p (tree);
 extern bool range_in_array_bounds_p (tree);
@@ -4937,7 +4937,7 @@ extern int real_minus_onep (const_tree);
 extern void init_ttree (void);
 extern void build_common_tree_nodes (bool, bool);
 extern void build_common_tree_nodes_2 (int);
-extern void build_common_builtin_nodes (void);
+extern void build_common_builtin_nodes (bool);
 extern tree build_nonstandard_integer_type (unsigned HOST_WIDE_INT, int);
 extern tree build_range_type (tree, tree, tree);
 extern bool subrange_type_for_debug_p (const_tree, tree *, tree *);
index 9774ca224f5b6aa515a9fa26f7b0007950cef643..9109286587c64802bbcef4abfb7819f27be3e1eb 100644 (file)
@@ -1087,84 +1087,86 @@ find_func_by_pid (int   pid)
  */
 
 static gimple
-gimple_ic (gimple stmt, gimple call, struct cgraph_node *direct_call, 
+gimple_ic (gimple icall_stmt, struct cgraph_node *direct_call, 
           int prob, gcov_type count, gcov_type all)
 {
-  gimple stmt1, stmt2, stmt3;
+  gimple dcall_stmt, load_stmt, cond_stmt;
   tree tmp1, tmpv, tmp;
-  gimple bb1end, bb2end, bb3end;
-  basic_block bb, bb2, bb3, bb4;
+  basic_block cond_bb, dcall_bb, icall_bb, join_bb;
   tree optype = build_pointer_type (void_type_node);
-  edge e12, e13, e23, e24, e34;
+  edge e_cd, e_ci, e_di, e_dj, e_ij;
   gimple_stmt_iterator gsi;
-  int region;
+  int lp_nr;
 
-  bb = gimple_bb (stmt);
-  gsi = gsi_for_stmt (stmt);
+  cond_bb = gimple_bb (icall_stmt);
+  gsi = gsi_for_stmt (icall_stmt);
 
   tmpv = create_tmp_var (optype, "PROF");
   tmp1 = create_tmp_var (optype, "PROF");
-  stmt1 = gimple_build_assign (tmpv, unshare_expr (gimple_call_fn (call)));
+  tmp = unshare_expr (gimple_call_fn (icall_stmt));
+  load_stmt = gimple_build_assign (tmpv, tmp);
+  gsi_insert_before (&gsi, load_stmt, GSI_SAME_STMT);
 
   tmp = fold_convert (optype, build_addr (direct_call->decl, 
                                          current_function_decl));
-  stmt2 = gimple_build_assign (tmp1, tmp);
-  stmt3 = gimple_build_cond (NE_EXPR, tmp1, tmpv, NULL_TREE, NULL_TREE);
-  gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT);
-  gsi_insert_before (&gsi, stmt2, GSI_SAME_STMT);
-  gsi_insert_before (&gsi, stmt3, GSI_SAME_STMT);
-  bb1end = stmt3;
+  load_stmt = gimple_build_assign (tmp1, tmp);
+  gsi_insert_before (&gsi, load_stmt, GSI_SAME_STMT);
 
-  stmt1 = gimple_copy (stmt);
-  gimple_call_set_fndecl (stmt1, direct_call->decl);
-  gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT);
-  bb2end = stmt1;
-  bb3end = stmt;
+  cond_stmt = gimple_build_cond (EQ_EXPR, tmp1, tmpv, NULL_TREE, NULL_TREE);
+  gsi_insert_before (&gsi, cond_stmt, GSI_SAME_STMT);
+
+  dcall_stmt = gimple_copy (icall_stmt);
+  gimple_call_set_fndecl (dcall_stmt, direct_call->decl);
+  gsi_insert_before (&gsi, dcall_stmt, GSI_SAME_STMT);
 
   /* Fix CFG. */
-  /* Edge e23 connects bb2 to bb3, etc. */
-  e12 = split_block (bb, bb1end);
-  bb2 = e12->dest;
-  bb2->count = count;
-  e23 = split_block (bb2, bb2end);
-  bb3 = e23->dest;
-  bb3->count = all - count;
-  e34 = split_block (bb3, bb3end);
-  bb4 = e34->dest;
-  bb4->count = all;
+  /* Edge e_cd connects cond_bb to dcall_bb, etc; note the first letters. */
+  e_cd = split_block (cond_bb, cond_stmt);
+  dcall_bb = e_cd->dest;
+  dcall_bb->count = count;
 
-  e12->flags &= ~EDGE_FALLTHRU;
-  e12->flags |= EDGE_FALSE_VALUE;
-  e12->probability = prob;
-  e12->count = count;
+  e_di = split_block (dcall_bb, dcall_stmt);
+  icall_bb = e_di->dest;
+  icall_bb->count = all - count;
 
-  e13 = make_edge (bb, bb3, EDGE_TRUE_VALUE);
-  e13->probability = REG_BR_PROB_BASE - prob;
-  e13->count = all - count;
+  e_ij = split_block (icall_bb, icall_stmt);
+  join_bb = e_ij->dest;
+  join_bb->count = all;
 
-  remove_edge (e23);
+  e_cd->flags = (e_cd->flags & ~EDGE_FALLTHRU) | EDGE_TRUE_VALUE;
+  e_cd->probability = prob;
+  e_cd->count = count;
+
+  e_ci = make_edge (cond_bb, icall_bb, EDGE_FALSE_VALUE);
+  e_ci->probability = REG_BR_PROB_BASE - prob;
+  e_ci->count = all - count;
+
+  remove_edge (e_di);
   
-  e24 = make_edge (bb2, bb4, EDGE_FALLTHRU);
-  e24->probability = REG_BR_PROB_BASE;
-  e24->count = count;
-  e34->probability = REG_BR_PROB_BASE;
-  e34->count = all - count;
+  e_dj = make_edge (dcall_bb, join_bb, EDGE_FALLTHRU);
+  e_dj->probability = REG_BR_PROB_BASE;
+  e_dj->count = count;
+
+  e_ij->probability = REG_BR_PROB_BASE;
+  e_ij->count = all - count;
 
   /* Fix eh edges */
-  region = lookup_stmt_eh_region (stmt);
-  if (region >= 0 && stmt_could_throw_p (stmt1))
+  lp_nr = lookup_stmt_eh_lp (icall_stmt);
+  if (lp_nr != 0)
     {
-      add_stmt_to_eh_region (stmt1, region);
-      make_eh_edges (stmt1);
-    }
+      gimple_purge_dead_eh_edges (join_bb);
 
-  if (region >= 0 && stmt_could_throw_p (stmt))
-    {
-      gimple_purge_dead_eh_edges (bb4);
-      make_eh_edges (stmt);
+      if (stmt_could_throw_p (dcall_stmt))
+       {
+         add_stmt_to_eh_lp (dcall_stmt, lp_nr);
+         make_eh_edges (dcall_stmt);
+       }
+
+      gcc_assert (stmt_could_throw_p (icall_stmt));
+      make_eh_edges (icall_stmt);
     }
 
-  return stmt1;
+  return dcall_stmt;
 }
 
 /*
@@ -1220,7 +1222,7 @@ gimple_ic_transform (gimple stmt)
   if (direct_call == NULL)
     return false;
 
-  modify = gimple_ic (stmt, stmt, direct_call, prob, count, all);
+  modify = gimple_ic (stmt, direct_call, prob, count, all);
 
   if (dump_file)
     {
@@ -1266,89 +1268,79 @@ interesting_stringop_to_profile_p (tree fndecl, gimple call)
     }
 }
 
-/* Convert   stringop (..., size)
+/* Convert   stringop (..., vcall_size)
    into 
-   if (size == VALUE)
-     stringop (...., VALUE);
+   if (vcall_size == icall_size)
+     stringop (..., icall_size);
    else
-     stringop (...., size);
-   assuming constant propagation of VALUE will happen later.
-*/
+     stringop (..., vcall_size);
+   assuming we'll propagate a true constant into ICALL_SIZE later.  */
+
 static void
-gimple_stringop_fixed_value (gimple stmt, tree value, int prob, gcov_type count,
-                          gcov_type all)
+gimple_stringop_fixed_value (gimple vcall_stmt, tree icall_size, int prob,
+                            gcov_type count, gcov_type all)
 {
-  gimple stmt1, stmt2, stmt3;
-  tree tmp1, tmpv;
-  gimple bb1end, bb2end;
-  basic_block bb, bb2, bb3, bb4;
-  edge e12, e13, e23, e24, e34;
+  gimple tmp_stmt, cond_stmt, icall_stmt;
+  tree tmp1, tmpv, vcall_size, optype;
+  basic_block cond_bb, icall_bb, vcall_bb, join_bb;
+  edge e_ci, e_cv, e_iv, e_ij, e_vj;
   gimple_stmt_iterator gsi;
-  tree blck_size = gimple_call_arg (stmt, 2);
-  tree optype = TREE_TYPE (blck_size);
-  int region;
 
-  bb = gimple_bb (stmt);
-  gsi = gsi_for_stmt (stmt);
+  cond_bb = gimple_bb (vcall_stmt);
+  gsi = gsi_for_stmt (vcall_stmt);
 
-  if (gsi_end_p (gsi))
-    {
-      edge_iterator ei;
-      for (ei = ei_start (bb->succs); (e34 = ei_safe_edge (ei)); )
-       if (!(e34->flags & EDGE_ABNORMAL))
-         break;
-    }
-  else
-    {
-      e34 = split_block (bb, stmt);
-      gsi = gsi_for_stmt (stmt);
-    }
-  bb4 = e34->dest;
+  vcall_size = gimple_call_arg (vcall_stmt, 2);
+  optype = TREE_TYPE (vcall_size);
 
   tmpv = create_tmp_var (optype, "PROF");
   tmp1 = create_tmp_var (optype, "PROF");
-  stmt1 = gimple_build_assign (tmpv, fold_convert (optype, value));
-  stmt2 = gimple_build_assign (tmp1, blck_size);
-  stmt3 = gimple_build_cond (NE_EXPR, tmp1, tmpv, NULL_TREE, NULL_TREE);
-  gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT);
-  gsi_insert_before (&gsi, stmt2, GSI_SAME_STMT);
-  gsi_insert_before (&gsi, stmt3, GSI_SAME_STMT);
-  bb1end = stmt3;
+  tmp_stmt = gimple_build_assign (tmpv, fold_convert (optype, icall_size));
+  gsi_insert_before (&gsi, tmp_stmt, GSI_SAME_STMT);
 
-  stmt1 = gimple_copy (stmt);
-  gimple_call_set_arg (stmt1, 2, value);
-  gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT);
-  region = lookup_stmt_eh_region (stmt);
-  if (region >= 0)
-    add_stmt_to_eh_region (stmt1, region);
-  bb2end = stmt1;
+  tmp_stmt = gimple_build_assign (tmp1, vcall_size);
+  gsi_insert_before (&gsi, tmp_stmt, GSI_SAME_STMT);
+
+  cond_stmt = gimple_build_cond (EQ_EXPR, tmp1, tmpv, NULL_TREE, NULL_TREE);
+  gsi_insert_before (&gsi, cond_stmt, GSI_SAME_STMT);
+
+  icall_stmt = gimple_copy (vcall_stmt);
+  gimple_call_set_arg (icall_stmt, 2, icall_size);
+  gsi_insert_before (&gsi, icall_stmt, GSI_SAME_STMT);
 
   /* Fix CFG. */
-  /* Edge e23 connects bb2 to bb3, etc. */
-  e12 = split_block (bb, bb1end);
-  bb2 = e12->dest;
-  bb2->count = count;
-  e23 = split_block (bb2, bb2end);
-  bb3 = e23->dest;
-  bb3->count = all - count;
+  /* Edge e_ci connects cond_bb to icall_bb, etc. */
+  e_ci = split_block (cond_bb, cond_stmt);
+  icall_bb = e_ci->dest;
+  icall_bb->count = count;
 
-  e12->flags &= ~EDGE_FALLTHRU;
-  e12->flags |= EDGE_FALSE_VALUE;
-  e12->probability = prob;
-  e12->count = count;
+  e_iv = split_block (icall_bb, icall_stmt);
+  vcall_bb = e_iv->dest;
+  vcall_bb->count = all - count;
 
-  e13 = make_edge (bb, bb3, EDGE_TRUE_VALUE);
-  e13->probability = REG_BR_PROB_BASE - prob;
-  e13->count = all - count;
+  e_vj = split_block (vcall_bb, vcall_stmt);
+  join_bb = e_vj->dest;
+  join_bb->count = all;
 
-  remove_edge (e23);
+  e_ci->flags = (e_ci->flags & ~EDGE_FALLTHRU) | EDGE_TRUE_VALUE;
+  e_ci->probability = prob;
+  e_ci->count = count;
+
+  e_cv = make_edge (cond_bb, vcall_bb, EDGE_FALSE_VALUE);
+  e_cv->probability = REG_BR_PROB_BASE - prob;
+  e_cv->count = all - count;
+
+  remove_edge (e_iv);
   
-  e24 = make_edge (bb2, bb4, EDGE_FALLTHRU);
-  e24->probability = REG_BR_PROB_BASE;
-  e24->count = count;
+  e_ij = make_edge (icall_bb, join_bb, EDGE_FALLTHRU);
+  e_ij->probability = REG_BR_PROB_BASE;
+  e_ij->count = count;
 
-  e34->probability = REG_BR_PROB_BASE;
-  e34->count = all - count;
+  e_vj->probability = REG_BR_PROB_BASE;
+  e_vj->count = all - count;
+
+  /* Because these are all string op builtins, they're all nothrow.  */
+  gcc_assert (!stmt_could_throw_p (vcall_stmt));
+  gcc_assert (!stmt_could_throw_p (icall_stmt));
 }
 
 /* Find values inside STMT for that we want to measure histograms for
index c546a2bff9b80974182f5f5e083bb0f4107fb548..e9ccc52bcb09e93142973e30dd7ed5750f297e66 100644 (file)
@@ -23,6 +23,11 @@ along with GCC; see the file COPYING3.  If not see
 DEF_VEC_I(char);
 DEF_VEC_ALLOC_I(char,heap);
 
+typedef unsigned char uchar;
+DEF_VEC_I(uchar);
+DEF_VEC_ALLOC_I(uchar,heap);
+DEF_VEC_ALLOC_I(uchar,gc);
+
 DEF_VEC_I(int);
 DEF_VEC_ALLOC_I(int,heap);
 
This page took 0.467158 seconds and 5 git commands to generate.