Paolo Bonzini wrote: >> I also wondered about this. I think the original idea is that splits >> can call into dojump.c. > > A more likely possibility is -fnon-call-exceptions.
Of course this is the main cause. But splitting one jump to multiple jumps is supported and actually even documented. It will happen for example in this testcase: int f(float x) { if (x != x) return 5; else abort (); } on i386 which produces fucomip %st(0), %st jp .L8 je .L6 It is possible to change this to an expander in the i386 md of course. I don't think any other backend is relying on it, but I will make a more thorough check if I end up submitting something like the attached patch. Paolo
2009-03-10 Paolo Bonzini <bonz...@gnu.org> * lower-subreg.c (decompose_multiword_subregs): Extract code... * cfgbuild.c (rtl_split_blocks_for_eh): ... here. * basic-block.h (rtl_split_blocks_for_eh): Declare it. * recog.c (split_insn): Return bool. Check that the splitter produces no barriers and no labels. (split_all_insns): Use the result. Call rtl_split_blocks_for_eh instead of find_many_sub_basic_blocks. * reload1.c (fixup_abnormal_edges): Use it. * passes.c (init_optimization_passes): Move cfglayout mode further down. Index: gcc/passes.c =================================================================== --- gcc/passes.c (branch combine-cfglayout) +++ gcc/passes.c (working copy) @@ -757,8 +757,8 @@ init_optimization_passes (void) NEXT_PASS (pass_if_after_combine); NEXT_PASS (pass_partition_blocks); NEXT_PASS (pass_regmove); - NEXT_PASS (pass_outof_cfg_layout_mode); NEXT_PASS (pass_split_all_insns); + NEXT_PASS (pass_outof_cfg_layout_mode); NEXT_PASS (pass_lower_subreg2); NEXT_PASS (pass_df_initialize_no_opt); NEXT_PASS (pass_stack_ptr_mod); Index: gcc/recog.c =================================================================== --- gcc/recog.c (branch combine-cfglayout) +++ gcc/recog.c (working copy) @@ -29,6 +29,7 @@ along with GCC; see the file COPYING3. #include "insn-config.h" #include "insn-attr.h" #include "hard-reg-set.h" +#include "except.h" #include "recog.h" #include "regs.h" #include "addresses.h" @@ -71,7 +72,6 @@ get_attr_enabled (rtx insn ATTRIBUTE_UNU static void validate_replace_rtx_1 (rtx *, rtx, rtx, rtx, bool); static void validate_replace_src_1 (rtx *, void *); -static rtx split_insn (rtx); /* Nonzero means allow operands to be volatile. This should be 0 if you are generating rtl, such as if you are calling @@ -2671,19 +2671,23 @@ reg_fits_class_p (rtx operand, enum reg_ } /* Split single instruction. Helper function for split_all_insns and - split_all_insns_noflow. Return last insn in the sequence if successful, - or NULL if unsuccessful. */ + split_all_insns_noflow. Return whether new control flow insns + were added. */ -static rtx +static bool split_insn (rtx insn) { /* Split insns here to get max fine-grain parallelism. */ rtx first = PREV_INSN (insn); rtx last = try_split (PATTERN (insn), insn, 1); rtx insn_set, last_set, note; + bool new_cfi = false; + bool was_cfi; if (last == insn) - return NULL_RTX; + return false; + + was_cfi = control_flow_insn_p (insn); /* If the original instruction was a single set that was known to be equivalent to a constant, see if we can say the same about the last @@ -2706,22 +2710,25 @@ split_insn (rtx insn) /* try_split returns the NOTE that INSN became. */ SET_INSN_DELETED (insn); - /* ??? Coddle to md files that generate subregs in post-reload - splitters instead of computing the proper hard register. */ - if (reload_completed && first != last) + while (first != last) { first = NEXT_INSN (first); - for (;;) + gcc_assert (!BARRIER_P (first) && !LABEL_P (first)); + + /* ??? Coddle to md files that generate subregs in post-reload + splitters instead of computing the proper hard register. */ + if (reload_completed && INSN_P (first)) + cleanup_subreg_operands (first); + if ((first != last || !was_cfi) + && control_flow_insn_p (first)) { - if (INSN_P (first)) - cleanup_subreg_operands (first); - if (first == last) - break; - first = NEXT_INSN (first); + gcc_assert (flag_non_call_exceptions + && can_throw_internal (first)); + new_cfi = true; } } - return last; + return new_cfi; } /* Split all insns in the function. If UPD_LIFE, update life info after. */ @@ -2730,12 +2737,10 @@ void split_all_insns (void) { sbitmap blocks; - bool changed; basic_block bb; blocks = sbitmap_alloc (last_basic_block); sbitmap_zero (blocks); - changed = false; FOR_EACH_BB_REVERSE (bb) { @@ -2753,41 +2758,17 @@ split_all_insns (void) { rtx set = single_set (insn); - /* Don't split no-op move insns. These should silently - disappear later in final. Splitting such insns would - break the code that handles LIBCALL blocks. */ if (set && set_noop_p (set)) - { - /* Nops get in the way while scheduling, so delete them - now if register allocation has already been done. It - is too risky to try to do this before register - allocation, and there are unlikely to be very many - nops then anyways. */ - if (reload_completed) - delete_insn_and_edges (insn); - } - else - { - rtx last = split_insn (insn); - if (last) - { - /* The split sequence may include barrier, but the - BB boundary we are interested in will be set to - previous one. */ - - while (BARRIER_P (last)) - last = PREV_INSN (last); - SET_BIT (blocks, bb->index); - changed = true; - } - } + delete_insn_and_edges (insn); + + else if (split_insn (insn)) + SET_BIT (blocks, bb->index); } } } default_rtl_profile (); - if (changed) - find_many_sub_basic_blocks (blocks); + rtl_split_blocks_for_eh (blocks, true); #ifdef ENABLE_CHECKING verify_flow_info (); Index: gcc/lower-subreg.c =================================================================== --- gcc/lower-subreg.c (branch combine-cfglayout) +++ gcc/lower-subreg.c (working copy) @@ -1139,8 +1139,6 @@ decompose_multiword_subregs (void) if (!bitmap_empty_p (decomposable_context)) { sbitmap sub_blocks; - unsigned int i; - sbitmap_iterator sbi; bitmap_iterator iter; unsigned int regno; @@ -1248,35 +1246,10 @@ decompose_multiword_subregs (void) } /* If we had insns to split that caused control flow insns in the middle - of a basic block, split those blocks now. Note that we only handle + of a basic block, split those blocks now. We only have to handle the case where splitting a load has caused multiple possibly trapping loads to appear. */ - EXECUTE_IF_SET_IN_SBITMAP (sub_blocks, 0, i, sbi) - { - rtx insn, end; - edge fallthru; - - bb = BASIC_BLOCK (i); - insn = BB_HEAD (bb); - end = BB_END (bb); - - while (insn != end) - { - if (control_flow_insn_p (insn)) - { - /* Split the block after insn. There will be a fallthru - edge, which is OK so we keep it. We have to create the - exception edges ourselves. */ - fallthru = split_block (bb, insn); - rtl_make_eh_edge (NULL, bb, BB_END (bb)); - bb = fallthru->dest; - insn = BB_HEAD (bb); - } - else - insn = NEXT_INSN (insn); - } - } - + rtl_split_blocks_for_eh (sub_blocks, true); sbitmap_free (sub_blocks); } Index: gcc/cfgbuild.c =================================================================== --- gcc/cfgbuild.c (branch combine-cfglayout) +++ gcc/cfgbuild.c (working copy) @@ -216,6 +216,53 @@ rtl_make_eh_edge (sbitmap edge_cache, ba free_INSN_LIST_list (&handlers); } +/* Look in BLOCKS for control flow insns in the middle of the basic block, + typically caused by splitting insns. The pass is skipped except for + -fnon-call-exceptions if NON_CALL_EXCEPTIONS_ONLY true. */ +void +rtl_split_blocks_for_eh (sbitmap blocks, bool non_call_exceptions_only) +{ + unsigned int i; + sbitmap_iterator sbi; + +#ifndef ENABLE_CHECKING + if (non_call_exceptions_only && !flag_non_call_exceptions) + return; +#endif + + EXECUTE_IF_SET_IN_SBITMAP (blocks, 0, i, sbi) + { + rtx insn, end; + edge fallthru; + basic_block bb; + + bb = BASIC_BLOCK (i); + insn = BB_HEAD (bb); + end = BB_END (bb); + + while (insn != end) + { + if (control_flow_insn_p (insn)) + { +#ifdef ENABLE_CHECKING + gcc_assert (!non_call_exceptions_only + || (flag_non_call_exceptions + && can_throw_internal (insn))); +#endif + /* Split the block after insn. There will be a fallthru + edge, which is OK so we keep it. We have to create the + exception edges ourselves. */ + fallthru = split_block (bb, insn); + rtl_make_eh_edge (NULL, bb, BB_END (bb)); + bb = fallthru->dest; + insn = BB_HEAD (bb); + } + else + insn = NEXT_INSN (insn); + } + } +} + /* States of basic block as seen by find_many_sub_basic_blocks. */ enum state { /* Basic blocks created via split_block belong to this state. Index: gcc/basic-block.h =================================================================== --- gcc/basic-block.h (branch combine-cfglayout) +++ gcc/basic-block.h (working copy) @@ -896,6 +896,7 @@ extern bool purge_dead_edges (basic_bloc /* In cfgbuild.c. */ extern void find_many_sub_basic_blocks (sbitmap); extern void rtl_make_eh_edge (sbitmap, basic_block, rtx); +extern void rtl_split_blocks_for_eh (sbitmap, bool); extern void find_basic_blocks (rtx); /* In cfgcleanup.c. */ Index: gcc/reload1.c =================================================================== --- gcc/reload1.c (branch combine-cfglayout) +++ gcc/reload1.c (working copy) @@ -8925,7 +8925,7 @@ fixup_abnormal_edges (void) sbitmap blocks; blocks = sbitmap_alloc (last_basic_block); sbitmap_ones (blocks); - find_many_sub_basic_blocks (blocks); + rtl_split_blocks_for_eh (blocks, true); sbitmap_free (blocks); }