> If we don't do it, we'll get another PR saying "this works in LTO mode with > other versions of the Ada compiler" (which is true) so I'll proceed.
Here is what I've installed after bootstrapping/regtesting on x86_64-suse-linux and i586-suse-linux. It adds the flag to 'struct function' and streams it. While I was at it, I also changed the trivially-dead-insns machinery in cse.c and dse.c to use the same predicate as dce.c, namely !insn_nothrow_p instead of insn_could_throw_p. The former is more precise and well suited to these optimization passes. cfgexpand.c and reload1.c keep using the latter when they are massaging the RTL stream. PR middle-end/53590 * common.opt (-fdelete-dead-exceptions): New switch. * doc/invoke.texi (Code Gen Options): Document it. * cse.c (count_reg_usage) <CALL_INSN>: Use !insn_nothrow_p in lieu of insn_could_throw_p predicate. Do not skip an insn that could throw if dead exceptions can be deleted. (insn_live_p): Likewise, do not return true in that case. * dce.c (can_alter_cfg): New flag. (deletable_insn_p): Do not return false for an insn that can throw if the CFG can be altered and dead exceptions can be deleted. (init_dce): Set can_alter_cfg to false for fast DCE, true otherwise. * dse.c (scan_insn): Use !insn_nothrow_p in lieu of insn_could_throw_ predicate. Do not preserve an insn that could throw if dead exceptions can be deleted. * function.h (struct function): Add can_delete_dead_exceptions flag. * function.c (allocate_struct_function): Set it. * lto-streamer-in.c (input_struct_function_base): Stream it. * lto-streamer-out.c (input_struct_function_base): Likewise. * tree-ssa-dce.c (mark_stmt_if_obviously_necessary): Do not mark a statement that could throw as necessary if dead exceptions can be deleted. ada/ * gcc-interface/misc.c (gnat_init_options_struct): Set opts->x_flag_delete_dead_exceptions to 1. -- Eric Botcazou
Index: doc/invoke.texi =================================================================== --- doc/invoke.texi (revision 188647) +++ doc/invoke.texi (working copy) @@ -975,7 +975,7 @@ See S/390 and zSeries Options. @xref{Code Gen Options,,Options for Code Generation Conventions}. @gccoptlist{-fcall-saved-@var{reg} -fcall-used-@var{reg} @gol -ffixed-@var{reg} -fexceptions @gol --fnon-call-exceptions -funwind-tables @gol +-fnon-call-exceptions -fdelete-dead-exceptions -funwind-tables @gol -fasynchronous-unwind-tables @gol -finhibit-size-directive -finstrument-functions @gol -finstrument-functions-exclude-function-list=@var{sym},@var{sym},@dots{} @gol @@ -19317,6 +19317,14 @@ instructions to throw exceptions, i.e.@: instructions. It does not allow exceptions to be thrown from arbitrary signal handlers such as @code{SIGALRM}. +@item -fdelete-dead-exceptions +@opindex fdelete-dead-exceptions +Consider that instructions that may throw exceptions but don't otherwise +contribute to the execution of the program can be optimized away. +This option is enabled by default for the Ada front end, as permitted by +the Ada language specification. +Optimization passes that cause dead exceptions to be removed are enabled independently at different optimization levels. + @item -funwind-tables @opindex funwind-tables Similar to @option{-fexceptions}, except that it just generates any needed Index: cse.c =================================================================== --- cse.c (revision 188647) +++ cse.c (working copy) @@ -599,7 +599,6 @@ static void invalidate_from_clobbers (rt static void invalidate_from_sets_and_clobbers (rtx); static rtx cse_process_notes (rtx, rtx, bool *); static void cse_extended_basic_block (struct cse_basic_block_data *); -static void count_reg_usage (rtx, int *, rtx, int); static int check_for_label_ref (rtx *, void *); extern void dump_class (struct table_elt*); static void get_cse_reg_info_1 (unsigned int regno); @@ -6692,10 +6691,11 @@ count_reg_usage (rtx x, int *counts, rtx case CALL_INSN: case INSN: case JUMP_INSN: - /* We expect dest to be NULL_RTX here. If the insn may trap, + /* We expect dest to be NULL_RTX here. If the insn may throw, or if it cannot be deleted due to side-effects, mark this fact by setting DEST to pc_rtx. */ - if (insn_could_throw_p (x) || side_effects_p (PATTERN (x))) + if ((!cfun->can_delete_dead_exceptions && !insn_nothrow_p (x)) + || side_effects_p (PATTERN (x))) dest = pc_rtx; if (code == CALL_INSN) count_reg_usage (CALL_INSN_FUNCTION_USAGE (x), counts, dest, incr); @@ -6800,7 +6800,7 @@ static bool insn_live_p (rtx insn, int *counts) { int i; - if (insn_could_throw_p (insn)) + if (!cfun->can_delete_dead_exceptions && !insn_nothrow_p (insn)) return true; else if (GET_CODE (PATTERN (insn)) == SET) return set_live_p (PATTERN (insn), insn, counts); Index: lto-streamer-out.c =================================================================== --- lto-streamer-out.c (revision 188647) +++ lto-streamer-out.c (working copy) @@ -761,6 +761,7 @@ output_struct_function_base (struct outp bp_pack_value (&bp, fn->returns_pcc_struct, 1); bp_pack_value (&bp, fn->returns_struct, 1); bp_pack_value (&bp, fn->can_throw_non_call_exceptions, 1); + bp_pack_value (&bp, fn->can_delete_dead_exceptions, 1); bp_pack_value (&bp, fn->always_inline_functions_inlined, 1); bp_pack_value (&bp, fn->after_inlining, 1); bp_pack_value (&bp, fn->stdarg, 1); Index: ada/gcc-interface/misc.c =================================================================== --- ada/gcc-interface/misc.c (revision 188647) +++ ada/gcc-interface/misc.c (working copy) @@ -167,6 +167,9 @@ gnat_init_options_struct (struct gcc_opt { /* Uninitialized really means uninitialized in Ada. */ opts->x_flag_zero_initialized_in_bss = 0; + + /* We can delete dead instructions that may throw exceptions in Ada. */ + opts->x_flag_delete_dead_exceptions = 1; } /* Initialize for option processing. */ Index: dse.c =================================================================== --- dse.c (revision 188647) +++ dse.c (working copy) @@ -2628,7 +2628,7 @@ scan_insn (bb_info_t bb_info, rtx insn) them. */ if ((GET_CODE (PATTERN (insn)) == CLOBBER) || volatile_refs_p (PATTERN (insn)) - || insn_could_throw_p (insn) + || (!cfun->can_delete_dead_exceptions && !insn_nothrow_p (insn)) || (RTX_FRAME_RELATED_P (insn)) || find_reg_note (insn, REG_FRAME_RELATED_EXPR, NULL_RTX)) insn_info->cannot_delete = true; Index: lto-streamer-in.c =================================================================== --- lto-streamer-in.c (revision 188647) +++ lto-streamer-in.c (working copy) @@ -803,6 +803,7 @@ input_struct_function_base (struct funct fn->returns_pcc_struct = bp_unpack_value (&bp, 1); fn->returns_struct = bp_unpack_value (&bp, 1); fn->can_throw_non_call_exceptions = bp_unpack_value (&bp, 1); + fn->can_delete_dead_exceptions = bp_unpack_value (&bp, 1); fn->always_inline_functions_inlined = bp_unpack_value (&bp, 1); fn->after_inlining = bp_unpack_value (&bp, 1); fn->stdarg = bp_unpack_value (&bp, 1); Index: function.c =================================================================== --- function.c (revision 188647) +++ function.c (working copy) @@ -4496,6 +4496,7 @@ allocate_struct_function (tree fndecl, b /* ??? This could be set on a per-function basis by the front-end but is this worth the hassle? */ cfun->can_throw_non_call_exceptions = flag_non_call_exceptions; + cfun->can_delete_dead_exceptions = flag_delete_dead_exceptions; } } Index: function.h =================================================================== --- function.h (revision 188647) +++ function.h (working copy) @@ -615,6 +615,10 @@ struct GTY(()) function { exceptions. */ unsigned int can_throw_non_call_exceptions : 1; + /* Nonzero if instructions that may throw exceptions but don't otherwise + contribute to the execution of the program can be deleted. */ + unsigned int can_delete_dead_exceptions : 1; + /* Fields below this point are not set for abstract functions; see allocate_struct_function. */ Index: common.opt =================================================================== --- common.opt (revision 188647) +++ common.opt (working copy) @@ -979,6 +979,10 @@ fdelayed-branch Common Report Var(flag_delayed_branch) Optimization Attempt to fill delay slots of branch instructions +fdelete-dead-exceptions +Common Report Var(flag_delete_dead_exceptions) Init(0) +Delete dead instructions that may throw exceptions + fdelete-null-pointer-checks Common Report Var(flag_delete_null_pointer_checks) Init(1) Optimization Delete useless null pointer checks Index: tree-ssa-dce.c =================================================================== --- tree-ssa-dce.c (revision 188647) +++ tree-ssa-dce.c (working copy) @@ -272,8 +272,10 @@ static void mark_stmt_if_obviously_necessary (gimple stmt, bool aggressive) { /* With non-call exceptions, we have to assume that all statements could - throw. If a statement may throw, it is inherently necessary. */ - if (cfun->can_throw_non_call_exceptions && stmt_could_throw_p (stmt)) + throw. If a statement could throw, it can be deemed necessary. */ + if (cfun->can_throw_non_call_exceptions + && !cfun->can_delete_dead_exceptions + && stmt_could_throw_p (stmt)) { mark_stmt_necessary (stmt, true); return; Index: dce.c =================================================================== --- dce.c (revision 188647) +++ dce.c (working copy) @@ -47,6 +47,9 @@ along with GCC; see the file COPYING3. we don't want to reenter it. */ static bool df_in_progress = false; +/* True if we are allowed to alter the CFG in this pass. */ +static bool can_alter_cfg = false; + /* Instructions that have been marked but whose dependencies have not yet been processed. */ static VEC(rtx,heap) *worklist; @@ -113,8 +116,9 @@ deletable_insn_p (rtx insn, bool fast, b if (!NONJUMP_INSN_P (insn)) return false; - /* Don't delete insns that can throw. */ - if (!insn_nothrow_p (insn)) + /* Don't delete insns that may throw if we cannot do so. */ + if (!(cfun->can_delete_dead_exceptions && can_alter_cfg) + && !insn_nothrow_p (insn)) return false; body = PATTERN (insn); @@ -711,7 +715,10 @@ init_dce (bool fast) { bitmap_obstack_initialize (&dce_blocks_bitmap_obstack); bitmap_obstack_initialize (&dce_tmp_bitmap_obstack); + can_alter_cfg = false; } + else + can_alter_cfg = true; marked = sbitmap_alloc (get_max_uid () + 1); sbitmap_zero (marked);