Squash commit of EH in gimple

From-SVN: r151696
This commit is contained in:
Richard Henderson 2009-09-14 12:18:58 -07:00 committed by Richard Henderson
parent 0c433c31b3
commit 1d65f45cfa
91 changed files with 4515 additions and 4838 deletions

View 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.

View 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 \

View 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>

View 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

View 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,

View 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. */

View 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);

View 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"

View 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 ();

View 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;

View 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);

View 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);
}
@ -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)

View 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)
{

View 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))

View 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);

View 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);

View 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>

View 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

View 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);

View File

@ -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);

View File

@ -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))
{

View File

@ -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;

View 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:

File diff suppressed because it is too large Load Diff

View 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;
/* The list of landing pads associated with this region. */
struct eh_landing_pad_d *landing_pads;
/* 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 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 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 void foreach_reachable_handler (int, bool, bool,
void (*) (struct eh_region_d *, void *),
void *);
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 collect_eh_region_array (void);
extern void expand_resx_stmt (gimple);
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);
/* If non-NULL, this is a function that returns an expression to be
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 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)

View 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. */

View 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:

View 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>

View 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 ();
}

View 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];
};

View 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. */

View 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;

View 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);
}

View 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;

View 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;

View 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));
}

View 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.

View 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)
static inline tree
gimple_eh_must_not_throw_fndecl (gimple gs)
{
GIMPLE_CHECK (gs, GIMPLE_EH_FILTER);
return gs->gsbase.subcode != 0;
GIMPLE_CHECK (gs, GIMPLE_EH_MUST_NOT_THROW);
return gs->gimple_eh_mnt.fndecl;
}
/* 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)
{
GIMPLE_CHECK (gs, GIMPLE_EH_FILTER);
gs->gsbase.subcode = (unsigned int) mntp;
}
/* 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

View 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

View 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)

View 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);
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);
/* 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");
}
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. */

View 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)));

View 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))

View 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

View 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>

View 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

View 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 ();

View 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",

View 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;

View 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])

View 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);

View 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>

View 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)". */

View 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;

View 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

View 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);

View 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);

View 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 (note)
copy_reg_eh_region_note_backward (note, attempt,
before_try);
if (x != BB_END (bb) && eh_edge)
{
edge nfte, nehe;
int flags;
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);
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;
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;
}
}
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. */

View 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

View 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.
---------------------------------------------------------------------- */

View File

@ -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 *);

View 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

View 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.

View 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" } } */

View 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" } } */

View 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" } } */

View 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" } }

View 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;
default: ;
case GIMPLE_EH_DISPATCH:
err |= verify_eh_dispatch_edge (stmt);
break;
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 */
walk_gimple_seq (gimple_omp_body (stmt), move_stmt_r, move_stmt_op, wi);
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;
p->remap_decls_p = save_remap_decls_p;
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;
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.from_context = cfun->decl;
d.to_context = dest_cfun->decl;
d.new_label_map = new_label_map;
d.remap_decls_p = true;
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;
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

View 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;

View 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;

File diff suppressed because it is too large Load Diff

View 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 */

View 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);

View 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

View 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))

View 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;

View 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))

View 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)

View 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);

View 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. */

View 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;

View 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:
{

View 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;
}

View 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;

View 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)

View 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

View 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;
switch (r->type)
{
case ERT_CLEANUP:
break;
/* 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)
{
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_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

View 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

View 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 *);

View 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 (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);
}
if (region >= 0 && stmt_could_throw_p (stmt))
{
gimple_purge_dead_eh_edges (bb4);
make_eh_edges (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

View 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);