parent
0c433c31b3
commit
1d65f45cfa
340
gcc/ChangeLog
340
gcc/ChangeLog
|
@ -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.
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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 ();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
55
gcc/cfgrtl.c
55
gcc/cfgrtl.c
|
@ -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))
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
23
gcc/dce.c
23
gcc/dce.c
|
@ -79,13 +79,7 @@ deletable_insn_p_1 (rtx body)
|
|||
return false;
|
||||
|
||||
default:
|
||||
if (volatile_refs_p (body))
|
||||
return false;
|
||||
|
||||
if (flag_non_call_exceptions && may_trap_p (body))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return !volatile_refs_p (body);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,6 +93,14 @@ deletable_insn_p (rtx insn, bool fast, bitmap arg_stores)
|
|||
rtx body, x;
|
||||
int i;
|
||||
|
||||
/* Don't delete jumps, notes and the like. */
|
||||
if (!NONJUMP_INSN_P (insn))
|
||||
return false;
|
||||
|
||||
/* Don't delete insns that can throw. */
|
||||
if (!insn_nothrow_p (insn))
|
||||
return false;
|
||||
|
||||
if (CALL_P (insn)
|
||||
/* We cannot delete calls inside of the recursive dce because
|
||||
this may cause basic blocks to be deleted and this messes up
|
||||
|
@ -113,13 +115,6 @@ deletable_insn_p (rtx insn, bool fast, bitmap arg_stores)
|
|||
&& !RTL_LOOPING_CONST_OR_PURE_CALL_P (insn)))
|
||||
return find_call_stack_args (insn, false, fast, arg_stores);
|
||||
|
||||
if (!NONJUMP_INSN_P (insn))
|
||||
return false;
|
||||
|
||||
/* Similarly, we cannot delete other insns that can throw either. */
|
||||
if (df_in_progress && flag_non_call_exceptions && can_throw_internal (insn))
|
||||
return false;
|
||||
|
||||
body = PATTERN (insn);
|
||||
switch (GET_CODE (body))
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
3943
gcc/except.c
3943
gcc/except.c
File diff suppressed because it is too large
Load Diff
306
gcc/except.h
306
gcc/except.h
|
@ -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)
|
||||
|
|
22
gcc/expr.c
22
gcc/expr.c
|
@ -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. */
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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 ();
|
||||
}
|
||||
|
||||
|
|
|
@ -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];
|
||||
};
|
||||
|
|
13
gcc/gcse.c
13
gcc/gcse.c
|
@ -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. */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
73
gcc/gimple.c
73
gcc/gimple.c
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
74
gcc/gimple.h
74
gcc/gimple.h
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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)));
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ();
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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])
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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)". */
|
||||
|
|
|
@ -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;
|
||||
|
|
33
gcc/optabs.c
33
gcc/optabs.c
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
52
gcc/recog.c
52
gcc/recog.c
|
@ -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. */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
---------------------------------------------------------------------- */
|
||||
|
|
|
@ -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 *);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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" } } */
|
||||
|
|
|
@ -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" } } */
|
||||
|
|
|
@ -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" } } */
|
||||
|
|
|
@ -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" } }
|
||||
|
|
349
gcc/tree-cfg.c
349
gcc/tree-cfg.c
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
2715
gcc/tree-eh.c
2715
gcc/tree-eh.c
File diff suppressed because it is too large
Load Diff
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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:
|
||||
{
|
||||
|
|
|
@ -617,10 +617,6 @@ valid_gimple_rhs_p (tree expr)
|
|||
return false;
|
||||
break;
|
||||
|
||||
case EXC_PTR_EXPR:
|
||||
case FILTER_EXPR:
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
118
gcc/tree.c
118
gcc/tree.c
|
@ -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
|
||||
|
|
10
gcc/tree.def
10
gcc/tree.def
|
@ -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
|
||||
|
|
14
gcc/tree.h
14
gcc/tree.h
|
@ -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 *);
|
||||
|
|
232
gcc/value-prof.c
232
gcc/value-prof.c
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue