diff options
author | rguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-03-28 12:14:26 +0000 |
---|---|---|
committer | rguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-03-28 12:14:26 +0000 |
commit | 79f958cbb1216fb4a56b690b85d8832da4044473 (patch) | |
tree | a016e8f205f21bb435691b9d07878f5480b9aee9 | |
parent | 58cf0091a5554627bfc2eb67025e0086e0f45d70 (diff) | |
download | gcc-79f958cbb1216fb4a56b690b85d8832da4044473.tar.gz |
2012-03-28 Richard Guenther <rguenther@suse.de>
* loop-init.c (loop_optimizer_init): If loops are preserved
perform incremental initialization of required loop features.
(loop_optimizer_finalize): If loops are to be preserved only
clean up optional loop features.
(rtl_loop_done): Forcefully free loops here.
* cgraph.c (cgraph_release_function_body): Forcefully free
loops.
* cfgexpand.c (expand_gimple_cond): Properly add new basic-blocks
to existing loops.
(construct_init_block): Likewise.
(construct_exit_block): Likewise.
(gimple_expand_cfg): Clear LOOP_CLOSED_SSA loop state. Cleanup
the CFG after expanding.
* cfgloop.c (verify_loop_structure): Calculate or verify
dominators. If we needed to calculate them, free them afterwards.
* tree-pass.h (PROP_loops): New define.
* tree-ssa-loop.c (pass_tree_loop_init): Provide PROP_loops.
* basic-block.h (CLEANUP_CFG_CHANGED): New.
* cfgcleanup.c (merge_blocks_move): Protect loop latches.
(cleanup_cfg): If we did something and have loops around, fix
them up.
* cse.c (rest_of_handle_cse_after_global_opts): Call cleanup_cfg
with CLEANUP_CFG_CHANGED.
* cfghooks.c (merge_blocks): If we merge a loop header into
its predecessor, update the loop structure.
(duplicate_block): If we copy a loop latch, adjust loop state
to note we may have multiple latches.
(delete_basic_block): Mark loops for fixup if we remove a loop.
* cfganal.c (forwarder_block_p): Protect loop latches, headers
and preheaders.
* cfgrtl.c (rtl_can_merge_blocks): Protect loop latches.
(cfg_layout_can_merge_blocks_p): Likewise.
* cprop.c (bypass_block): If we create a loop with multiple
entries, mark it for removal.
* except.c (emit_to_new_bb_before): Add the new basic-block
to existing loops.
* tree-eh.c (lower_resx): Likewise.
* omp-low.c (finalize_task_copyfn): Do not copy PROP_loops.
(expand_omp_taskreg): Likewise.
* tree-inline.c (initialize_cfun): Likewise.
* tree-mudflap.c (add_bb_to_loop): Prototype.
(mf_build_check_statement_for): Properly add new basic-blocks
to existing loops.
* tree-ssa-threadupdate.c (thread_block): Mark loops for fixup
if we remove a loop.
(thread_through_loop_header): Likewise.
* trans-mem.c (tm_log_emit_save_or_restores): Properly add
new basic-blocks to existing loops.
(expand_transaction): Likewise.
* Makefile.in (except.o): Add $(CFGLOOP_H).
(expr.o): Likewise.
(cgraph.o): Likewise.
(cprop.o): Likewise.
(cfgexpand.o): Likewise.
(cfganal.o): Likewise.
(trans-mem.o): Likewise.
(tree-eh.o): Likewise.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@185913 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/ChangeLog | 60 | ||||
-rw-r--r-- | gcc/Makefile.in | 16 | ||||
-rw-r--r-- | gcc/basic-block.h | 1 | ||||
-rw-r--r-- | gcc/cfganal.c | 12 | ||||
-rw-r--r-- | gcc/cfgcleanup.c | 22 | ||||
-rw-r--r-- | gcc/cfgexpand.c | 9 | ||||
-rw-r--r-- | gcc/cfghooks.c | 25 | ||||
-rw-r--r-- | gcc/cfgloop.c | 10 | ||||
-rw-r--r-- | gcc/cfgloopmanip.c | 2 | ||||
-rw-r--r-- | gcc/cfgrtl.c | 8 | ||||
-rw-r--r-- | gcc/cgraph.c | 8 | ||||
-rw-r--r-- | gcc/cprop.c | 12 | ||||
-rw-r--r-- | gcc/cse.c | 6 | ||||
-rw-r--r-- | gcc/except.c | 12 | ||||
-rw-r--r-- | gcc/loop-init.c | 47 | ||||
-rw-r--r-- | gcc/omp-low.c | 4 | ||||
-rw-r--r-- | gcc/trans-mem.c | 11 | ||||
-rw-r--r-- | gcc/tree-cfgcleanup.c | 1 | ||||
-rw-r--r-- | gcc/tree-eh.c | 3 | ||||
-rw-r--r-- | gcc/tree-inline.c | 2 | ||||
-rw-r--r-- | gcc/tree-mudflap.c | 6 | ||||
-rw-r--r-- | gcc/tree-pass.h | 1 | ||||
-rw-r--r-- | gcc/tree-ssa-loop.c | 2 | ||||
-rw-r--r-- | gcc/tree-ssa-threadupdate.c | 2 |
24 files changed, 252 insertions, 30 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2491a8cdf16..3509bda2259 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,63 @@ +2012-03-28 Richard Guenther <rguenther@suse.de> + + * loop-init.c (loop_optimizer_init): If loops are preserved + perform incremental initialization of required loop features. + (loop_optimizer_finalize): If loops are to be preserved only + clean up optional loop features. + (rtl_loop_done): Forcefully free loops here. + * cgraph.c (cgraph_release_function_body): Forcefully free + loops. + * cfgexpand.c (expand_gimple_cond): Properly add new basic-blocks + to existing loops. + (construct_init_block): Likewise. + (construct_exit_block): Likewise. + (gimple_expand_cfg): Clear LOOP_CLOSED_SSA loop state. Cleanup + the CFG after expanding. + * cfgloop.c (verify_loop_structure): Calculate or verify + dominators. If we needed to calculate them, free them afterwards. + * tree-pass.h (PROP_loops): New define. + * tree-ssa-loop.c (pass_tree_loop_init): Provide PROP_loops. + * basic-block.h (CLEANUP_CFG_CHANGED): New. + * cfgcleanup.c (merge_blocks_move): Protect loop latches. + (cleanup_cfg): If we did something and have loops around, fix + them up. + * cse.c (rest_of_handle_cse_after_global_opts): Call cleanup_cfg + with CLEANUP_CFG_CHANGED. + * cfghooks.c (merge_blocks): If we merge a loop header into + its predecessor, update the loop structure. + (duplicate_block): If we copy a loop latch, adjust loop state + to note we may have multiple latches. + (delete_basic_block): Mark loops for fixup if we remove a loop. + * cfganal.c (forwarder_block_p): Protect loop latches, headers + and preheaders. + * cfgrtl.c (rtl_can_merge_blocks): Protect loop latches. + (cfg_layout_can_merge_blocks_p): Likewise. + * cprop.c (bypass_block): If we create a loop with multiple + entries, mark it for removal. + * except.c (emit_to_new_bb_before): Add the new basic-block + to existing loops. + * tree-eh.c (lower_resx): Likewise. + * omp-low.c (finalize_task_copyfn): Do not copy PROP_loops. + (expand_omp_taskreg): Likewise. + * tree-inline.c (initialize_cfun): Likewise. + * tree-mudflap.c (add_bb_to_loop): Prototype. + (mf_build_check_statement_for): Properly add new basic-blocks + to existing loops. + * tree-ssa-threadupdate.c (thread_block): Mark loops for fixup + if we remove a loop. + (thread_through_loop_header): Likewise. + * trans-mem.c (tm_log_emit_save_or_restores): Properly add + new basic-blocks to existing loops. + (expand_transaction): Likewise. + * Makefile.in (except.o): Add $(CFGLOOP_H). + (expr.o): Likewise. + (cgraph.o): Likewise. + (cprop.o): Likewise. + (cfgexpand.o): Likewise. + (cfganal.o): Likewise. + (trans-mem.o): Likewise. + (tree-eh.o): Likewise. + 2012-03-28 Georg-Johann Lay <avr@gjlay.de> PR target/52692 diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 716b3a43d2a..d50faccca52 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -2159,7 +2159,7 @@ trans-mem.o : trans-mem.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ $(TREE_H) $(GIMPLE_H) $(TREE_FLOW_H) $(TREE_PASS_H) $(TREE_INLINE_H) \ $(DIAGNOSTIC_CORE_H) $(DEMANGLE_H) output.h $(TRANS_MEM_H) \ $(PARAMS_H) $(TARGET_H) langhooks.h \ - tree-pretty-print.h gimple-pretty-print.h + tree-pretty-print.h gimple-pretty-print.h $(CFGLOOP_H) ggc-common.o: ggc-common.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ $(GGC_H) $(HASHTAB_H) $(DIAGNOSTIC_CORE_H) $(PARAMS_H) hosthooks.h \ @@ -2468,7 +2468,8 @@ tree-ssa-operands.o : tree-ssa-operands.c $(TREE_FLOW_H) $(CONFIG_H) \ tree-eh.o : tree-eh.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ $(TREE_H) $(TM_H) $(FLAGS_H) $(FUNCTION_H) $(EXCEPT_H) langhooks.h \ $(GGC_H) $(TREE_PASS_H) coretypes.h $(TIMEVAR_H) pointer-set.h \ - $(TREE_DUMP_H) $(TREE_INLINE_H) tree-iterator.h toplev.h $(DIAGNOSTIC_CORE_H) + $(TREE_DUMP_H) $(TREE_INLINE_H) tree-iterator.h toplev.h \ + $(DIAGNOSTIC_CORE_H) $(CFGLOOP_H) tree-ssa-loop.o : tree-ssa-loop.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(TREE_H) $(TM_P_H) $(BASIC_BLOCK_H) output.h \ $(DIAGNOSTIC_H) $(TREE_FLOW_H) $(TREE_DUMP_H) $(TREE_PASS_H) $(TIMEVAR_H) \ @@ -2814,7 +2815,7 @@ except.o : except.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ dwarf2asm.h dwarf2out.h toplev.h $(DIAGNOSTIC_CORE_H) $(HASHTAB_H) intl.h $(GGC_H) \ gt-except.h $(CGRAPH_H) $(INTEGRATE_H) $(DIAGNOSTIC_H) $(DWARF2_H) \ $(TARGET_H) $(TM_P_H) $(TREE_PASS_H) $(TIMEVAR_H) $(TREE_FLOW_H) \ - tree-pretty-print.h sbitmap.h $(COMMON_TARGET_H) + tree-pretty-print.h sbitmap.h $(COMMON_TARGET_H) $(CFGLOOP_H) expr.o : expr.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ $(TREE_H) $(FLAGS_H) $(FUNCTION_H) $(REGS_H) $(EXPR_H) $(OPTABS_H) \ $(LIBFUNCS_H) $(INSN_ATTR_H) insn-config.h $(RECOG_H) output.h \ @@ -2912,7 +2913,7 @@ cgraph.o : cgraph.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ gt-cgraph.h output.h intl.h $(BASIC_BLOCK_H) debug.h $(HASHTAB_H) \ $(TREE_INLINE_H) $(TREE_DUMP_H) $(TREE_FLOW_H) cif-code.def \ value-prof.h $(EXCEPT_H) $(IPA_UTILS_H) $(DIAGNOSTIC_CORE_H) \ - ipa-inline.h $(LTO_STREAMER_H) + ipa-inline.h $(LTO_STREAMER_H) $(CFGLOOP_H) cgraphunit.o : cgraphunit.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(TREE_H) langhooks.h $(TREE_INLINE_H) toplev.h $(DIAGNOSTIC_CORE_H) $(FLAGS_H) $(GGC_H) \ $(TARGET_H) $(CGRAPH_H) intl.h pointer-set.h $(FUNCTION_H) $(GIMPLE_H) \ @@ -3029,7 +3030,7 @@ cprop.o : cprop.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ $(RECOG_H) $(EXPR_H) $(BASIC_BLOCK_H) $(FUNCTION_H) output.h toplev.h $(DIAGNOSTIC_CORE_H) \ $(TM_P_H) $(PARAMS_H) cselib.h $(EXCEPT_H) $(TREE_H) $(TIMEVAR_H) \ intl.h $(OBSTACK_H) $(TREE_PASS_H) $(DF_H) $(DBGCNT_H) $(TARGET_H) \ - $(DF_H) + $(DF_H) $(CFGLOOP_H) gcse.o : gcse.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ $(REGS_H) hard-reg-set.h $(FLAGS_H) insn-config.h $(GGC_H) \ $(RECOG_H) $(EXPR_H) $(BASIC_BLOCK_H) $(FUNCTION_H) output.h toplev.h $(DIAGNOSTIC_CORE_H) \ @@ -3149,7 +3150,7 @@ cfgexpand.o : cfgexpand.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ $(DIAGNOSTIC_H) toplev.h $(DIAGNOSTIC_CORE_H) $(BASIC_BLOCK_H) $(FLAGS_H) debug.h $(PARAMS_H) \ value-prof.h $(TREE_INLINE_H) $(TARGET_H) $(SSAEXPAND_H) $(REGS_H) \ tree-pretty-print.h gimple-pretty-print.h $(BITMAP_H) sbitmap.h \ - $(INSN_ATTR_H) $(INTEGRATE_H) + $(INSN_ATTR_H) $(INTEGRATE_H) $(CFGLOOP_H) cfgrtl.o : cfgrtl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_ERROR_H) \ $(FLAGS_H) insn-config.h $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h \ output.h $(FUNCTION_H) $(EXCEPT_H) $(TM_P_H) $(INSN_ATTR_H) \ @@ -3158,7 +3159,8 @@ cfgrtl.o : cfgrtl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_ERROR_H) \ $(TREE_PASS_H) $(DF_H) $(GGC_H) $(COMMON_TARGET_H) cfganal.o : cfganal.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ $(BASIC_BLOCK_H) hard-reg-set.h insn-config.h $(RECOG_H) $(TM_P_H) \ - $(TIMEVAR_H) $(OBSTACK_H) $(DIAGNOSTIC_CORE_H) vecprim.h sbitmap.h $(BITMAP_H) + $(TIMEVAR_H) $(OBSTACK_H) $(DIAGNOSTIC_CORE_H) vecprim.h sbitmap.h \ + $(BITMAP_H) $(CFGLOOP_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 $(DIAGNOSTIC_CORE_H) \ $(FUNCTION_H) $(EXCEPT_H) $(TIMEVAR_H) $(TREE_H) $(EXPR_H) sbitmap.h diff --git a/gcc/basic-block.h b/gcc/basic-block.h index 3ff1cd645ea..fb17bad9d05 100644 --- a/gcc/basic-block.h +++ b/gcc/basic-block.h @@ -741,6 +741,7 @@ edge find_edge (basic_block, basic_block); #define CLEANUP_NO_INSN_DEL 16 /* Do not try to delete trivially dead insns. */ #define CLEANUP_CFGLAYOUT 32 /* Do cleanup in cfglayout mode. */ +#define CLEANUP_CFG_CHANGED 64 /* The caller changed the CFG. */ /* In lcm.c */ extern struct edge_list *pre_edge_lcm (int, sbitmap *, sbitmap *, diff --git a/gcc/cfganal.c b/gcc/cfganal.c index e27bbb2c6be..d361ff08f98 100644 --- a/gcc/cfganal.c +++ b/gcc/cfganal.c @@ -37,6 +37,7 @@ along with GCC; see the file COPYING3. If not see #include "bitmap.h" #include "sbitmap.h" #include "timevar.h" +#include "cfgloop.h" /* Store the data structures necessary for depth-first search. */ struct depth_first_search_dsS { @@ -94,6 +95,17 @@ forwarder_block_p (const_basic_block bb) || !single_succ_p (bb)) return false; + /* Protect loop latches, headers and preheaders. */ + if (current_loops) + { + basic_block dest; + if (bb->loop_father->header == bb) + return false; + dest = EDGE_SUCC (bb, 0)->dest; + if (dest->loop_father->header == dest) + return false; + } + for (insn = BB_HEAD (bb); insn != BB_END (bb); insn = NEXT_INSN (insn)) if (INSN_P (insn) && flow_active_insn_p (insn)) return false; diff --git a/gcc/cfgcleanup.c b/gcc/cfgcleanup.c index c695878802c..3824797485d 100644 --- a/gcc/cfgcleanup.c +++ b/gcc/cfgcleanup.c @@ -779,6 +779,11 @@ merge_blocks_move (edge e, basic_block b, basic_block c, int mode) if (e->flags & EDGE_FALLTHRU) { int b_index = b->index, c_index = c->index; + + /* Protect the loop latches. */ + if (current_loops && c->loop_father->latch == c) + return NULL; + merge_blocks (b, c); update_forwarder_flag (b); @@ -2976,6 +2981,23 @@ cleanup_cfg (int mode) if (!(mode & CLEANUP_CFGLAYOUT)) delete_dead_jumptables (); + /* ??? We probably do this way too often. */ + if (current_loops + && (changed + || (mode & CLEANUP_CFG_CHANGED))) + { + bitmap changed_bbs; + timevar_push (TV_REPAIR_LOOPS); + /* The above doesn't preserve dominance info if available. */ + gcc_assert (!dom_info_available_p (CDI_DOMINATORS)); + calculate_dominance_info (CDI_DOMINATORS); + changed_bbs = BITMAP_ALLOC (NULL); + fix_loop_structure (changed_bbs); + BITMAP_FREE (changed_bbs); + free_dominance_info (CDI_DOMINATORS); + timevar_pop (TV_REPAIR_LOOPS); + } + timevar_pop (TV_CLEANUP_CFG); return changed; diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index 75d2b162865..d148853143b 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -47,6 +47,7 @@ along with GCC; see the file COPYING3. If not see #include "ssaexpand.h" #include "bitmap.h" #include "sbitmap.h" +#include "cfgloop.h" #include "regs.h" /* For reg_renumber. */ #include "integrate.h" /* For emit_initial_value_sets. */ #include "insn-attr.h" /* For INSN_SCHEDULING. */ @@ -1940,6 +1941,8 @@ expand_gimple_cond (basic_block bb, gimple stmt) false_edge->flags |= EDGE_FALLTHRU; new_bb->count = false_edge->count; new_bb->frequency = EDGE_FREQUENCY (false_edge); + if (current_loops && bb->loop_father) + add_bb_to_loop (new_bb, bb->loop_father); new_edge = make_edge (new_bb, dest, 0); new_edge->probability = REG_BR_PROB_BASE; new_edge->count = new_bb->count; @@ -4118,6 +4121,8 @@ construct_init_block (void) ENTRY_BLOCK_PTR); init_block->frequency = ENTRY_BLOCK_PTR->frequency; init_block->count = ENTRY_BLOCK_PTR->count; + if (current_loops && ENTRY_BLOCK_PTR->loop_father) + add_bb_to_loop (init_block, ENTRY_BLOCK_PTR->loop_father); if (e) { first_block = e->dest; @@ -4185,6 +4190,8 @@ construct_exit_block (void) EXIT_BLOCK_PTR->prev_bb); exit_block->frequency = EXIT_BLOCK_PTR->frequency; exit_block->count = EXIT_BLOCK_PTR->count; + if (current_loops && EXIT_BLOCK_PTR->loop_father) + add_bb_to_loop (exit_block, EXIT_BLOCK_PTR->loop_father); ix = 0; while (ix < EDGE_COUNT (EXIT_BLOCK_PTR->preds)) @@ -4556,6 +4563,8 @@ gimple_expand_cfg (void) timevar_push (TV_POST_EXPAND); /* We are no longer in SSA form. */ cfun->gimple_df->in_ssa_p = false; + if (current_loops) + loops_state_clear (LOOP_CLOSED_SSA); /* Expansion is used by optimization passes too, set maybe_hot_insn_p conservatively to true until they are all profile aware. */ diff --git a/gcc/cfghooks.c b/gcc/cfghooks.c index c4c51cc4404..1dca79a70cf 100644 --- a/gcc/cfghooks.c +++ b/gcc/cfghooks.c @@ -508,6 +508,7 @@ delete_basic_block (basic_block bb) { loop->header = NULL; loop->latch = NULL; + loops_state_set (LOOPS_NEED_FIXUP); } remove_bb_from_loops (bb); @@ -682,8 +683,18 @@ merge_blocks (basic_block a, basic_block b) cfg_hooks->merge_blocks (a, b); + /* If we merge a loop header into its predecessor, update the loop + structure. */ if (current_loops != NULL) - remove_bb_from_loops (b); + { + if (b->loop_father->header == b) + { + remove_bb_from_loops (a); + add_bb_to_loop (a, b->loop_father); + a->loop_father->header = a; + } + remove_bb_from_loops (b); + } /* Normally there should only be one successor of A and that is B, but partway though the merge of blocks for conditional_execution we'll @@ -999,6 +1010,18 @@ duplicate_block (basic_block bb, edge e, basic_block after) struct loop *cloop = bb->loop_father; struct loop *copy = get_loop_copy (cloop); add_bb_to_loop (new_bb, copy ? copy : cloop); + /* If we copied the loop latch block but not the loop, adjust + loop state. + ??? If we copied the loop header block but not the loop + we might either have created a loop copy or a loop with + multiple entries. In both cases we probably have to + ditch the loops and arrange for a fixup. */ + if (!copy + && cloop->latch == bb) + { + cloop->latch = NULL; + loops_state_set (LOOPS_MAY_HAVE_MULTIPLE_LATCHES); + } } return new_bb; diff --git a/gcc/cfgloop.c b/gcc/cfgloop.c index 160486f13b1..94ba874b101 100644 --- a/gcc/cfgloop.c +++ b/gcc/cfgloop.c @@ -1317,9 +1317,13 @@ verify_loop_structure (void) unsigned num = number_of_loops (); loop_iterator li; struct loop_exit *exit, *mexit; + bool dom_available = dom_info_available_p (CDI_DOMINATORS); - /* We need up-to-date dominators, verify them. */ - verify_dominators (CDI_DOMINATORS); + /* We need up-to-date dominators, compute or verify them. */ + if (!dom_available) + calculate_dominance_info (CDI_DOMINATORS); + else + verify_dominators (CDI_DOMINATORS); /* Check sizes. */ sizes = XCNEWVEC (unsigned, num); @@ -1563,6 +1567,8 @@ verify_loop_structure (void) gcc_assert (!err); free (sizes); + if (!dom_available) + free_dominance_info (CDI_DOMINATORS); } /* Returns latch edge of LOOP. */ diff --git a/gcc/cfgloopmanip.c b/gcc/cfgloopmanip.c index 33bcf4b9872..5292ae536b5 100644 --- a/gcc/cfgloopmanip.c +++ b/gcc/cfgloopmanip.c @@ -1728,6 +1728,8 @@ fix_loop_structure (bitmap changed_bbs) if (record_exits) record_loop_exits (); + loops_state_clear (LOOPS_NEED_FIXUP); + #ifdef ENABLE_CHECKING verify_loop_structure (); #endif diff --git a/gcc/cfgrtl.c b/gcc/cfgrtl.c index b86cc74b6a4..ea293933704 100644 --- a/gcc/cfgrtl.c +++ b/gcc/cfgrtl.c @@ -727,6 +727,10 @@ rtl_can_merge_blocks (basic_block a, basic_block b) if (BB_PARTITION (a) != BB_PARTITION (b)) return false; + /* Protect the loop latches. */ + if (current_loops && b->loop_father->latch == b) + return false; + /* There must be exactly one edge in between the blocks. */ return (single_succ_p (a) && single_succ (a) == b @@ -2786,6 +2790,10 @@ cfg_layout_can_merge_blocks_p (basic_block a, basic_block b) if (BB_PARTITION (a) != BB_PARTITION (b)) return false; + /* Protect the loop latches. */ + if (current_loops && b->loop_father->latch == b) + return false; + /* If we would end up moving B's instructions, make sure it doesn't fall through into the exit block, since we cannot recover from a fallthrough edge into the exit block occurring in the middle of a function. */ diff --git a/gcc/cgraph.c b/gcc/cgraph.c index 7c44c059245..e429a91d82e 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -99,6 +99,7 @@ The callgraph: #include "ipa-utils.h" #include "lto-streamer.h" #include "ipa-inline.h" +#include "cfgloop.h" const char * const ld_plugin_symbol_resolution_names[]= { @@ -1363,6 +1364,12 @@ cgraph_release_function_body (struct cgraph_node *node) { tree old_decl = current_function_decl; push_cfun (DECL_STRUCT_FUNCTION (node->decl)); + if (cfun->cfg + && current_loops) + { + cfun->curr_properties &= ~PROP_loops; + loop_optimizer_finalize (); + } if (cfun->gimple_df) { current_function_decl = node->decl; @@ -1379,7 +1386,6 @@ cgraph_release_function_body (struct cgraph_node *node) } if (cfun->value_histograms) free_histograms (); - gcc_assert (!current_loops); pop_cfun(); gimple_set_body (node->decl, NULL); VEC_free (ipa_opt_pass, heap, diff --git a/gcc/cprop.c b/gcc/cprop.c index 01f40f0bc72..024dd207655 100644 --- a/gcc/cprop.c +++ b/gcc/cprop.c @@ -48,6 +48,7 @@ along with GCC; see the file COPYING3. If not see #include "df.h" #include "dbgcnt.h" #include "target.h" +#include "cfgloop.h" /* An obstack for our working variables. */ @@ -1610,6 +1611,17 @@ bypass_block (basic_block bb, rtx setcc, rtx jump) && dest != old_dest && dest != EXIT_BLOCK_PTR) { + if (current_loops != NULL + && e->src->loop_father->latch == e->src) + { + /* ??? Now we are creating (or may create) a loop + with multiple entries. Simply mark it for + removal. Alternatively we could not do this + threading. */ + e->src->loop_father->header = NULL; + e->src->loop_father->latch = NULL; + } + redirect_edge_and_branch_force (e, dest); /* Copy the register setter to the redirected edge. diff --git a/gcc/cse.c b/gcc/cse.c index a4145907183..d8f07e95eac 100644 --- a/gcc/cse.c +++ b/gcc/cse.c @@ -7451,7 +7451,7 @@ rest_of_handle_cse (void) { timevar_push (TV_JUMP); rebuild_jump_labels (get_insns ()); - cleanup_cfg (0); + cleanup_cfg (CLEANUP_CFG_CHANGED); timevar_pop (TV_JUMP); } else if (tem == 1 || optimize > 1) @@ -7511,7 +7511,7 @@ rest_of_handle_cse2 (void) { timevar_push (TV_JUMP); rebuild_jump_labels (get_insns ()); - cleanup_cfg (0); + cleanup_cfg (CLEANUP_CFG_CHANGED); timevar_pop (TV_JUMP); } else if (tem == 1) @@ -7572,7 +7572,7 @@ rest_of_handle_cse_after_global_opts (void) { timevar_push (TV_JUMP); rebuild_jump_labels (get_insns ()); - cleanup_cfg (0); + cleanup_cfg (CLEANUP_CFG_CHANGED); timevar_pop (TV_JUMP); } else if (tem == 1) diff --git a/gcc/except.c b/gcc/except.c index eb27648786c..ddc865217bd 100644 --- a/gcc/except.c +++ b/gcc/except.c @@ -144,6 +144,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-pass.h" #include "timevar.h" #include "tree-flow.h" +#include "cfgloop.h" /* Provide defaults for stuff that may not be defined when using sjlj exceptions. */ @@ -898,7 +899,7 @@ static basic_block emit_to_new_bb_before (rtx seq, rtx insn) { rtx last; - basic_block bb; + basic_block bb, prev_bb; edge e; edge_iterator ei; @@ -913,9 +914,16 @@ emit_to_new_bb_before (rtx seq, rtx insn) last = emit_insn_before (seq, insn); if (BARRIER_P (last)) last = PREV_INSN (last); - bb = create_basic_block (seq, last, BLOCK_FOR_INSN (insn)->prev_bb); + prev_bb = BLOCK_FOR_INSN (insn)->prev_bb; + bb = create_basic_block (seq, last, prev_bb); update_bb_for_insn (bb); bb->flags |= BB_SUPERBLOCK; + if (current_loops) + { + add_bb_to_loop (bb, prev_bb->loop_father); + if (prev_bb->loop_father->header == prev_bb) + prev_bb->loop_father->header = bb; + } return bb; } diff --git a/gcc/loop-init.c b/gcc/loop-init.c index daf5fa07410..b8d7b7ee7ce 100644 --- a/gcc/loop-init.c +++ b/gcc/loop-init.c @@ -42,15 +42,28 @@ along with GCC; see the file COPYING3. If not see void loop_optimizer_init (unsigned flags) { - struct loops *loops; + if (!current_loops) + { + struct loops *loops = ggc_alloc_cleared_loops (); + + gcc_assert (!(cfun->curr_properties & PROP_loops)); - gcc_assert (!current_loops); - loops = ggc_alloc_cleared_loops (); + /* Find the loops. */ - /* Find the loops. */ + flow_loops_find (loops); + current_loops = loops; + } + else + { + gcc_assert (cfun->curr_properties & PROP_loops); - flow_loops_find (loops); - current_loops = loops; + /* Ensure that the dominators are computed, like flow_loops_find does. */ + calculate_dominance_info (CDI_DOMINATORS); + +#ifdef ENABLE_CHECKING + verify_loop_structure (); +#endif + } if (flags & LOOPS_MAY_HAVE_MULTIPLE_LATCHES) { @@ -104,6 +117,22 @@ loop_optimizer_finalize (void) struct loop *loop; basic_block bb; + if (loops_state_satisfies_p (LOOPS_HAVE_RECORDED_EXITS)) + release_recorded_exits (); + + /* If we should preserve loop structure, do not free it but clear + flags that advanced properties are there as we are not preserving + that in full. */ + if (cfun->curr_properties & PROP_loops) + { + loops_state_clear (LOOP_CLOSED_SSA + | LOOPS_HAVE_MARKED_IRREDUCIBLE_REGIONS + | LOOPS_HAVE_PREHEADERS + | LOOPS_HAVE_SIMPLE_LATCHES + | LOOPS_HAVE_FALLTHRU_PREHEADERS); + return; + } + gcc_assert (current_loops != NULL); FOR_EACH_LOOP (li, loop, 0) @@ -112,8 +141,6 @@ loop_optimizer_finalize (void) } /* Clean up. */ - if (loops_state_satisfies_p (LOOPS_HAVE_RECORDED_EXITS)) - release_recorded_exits (); flow_loops_free (current_loops); ggc_free (current_loops); current_loops = NULL; @@ -200,6 +227,8 @@ struct rtl_opt_pass pass_rtl_loop_init = static unsigned int rtl_loop_done (void) { + /* No longer preserve loops, remove them now. */ + cfun->curr_properties &= ~PROP_loops; loop_optimizer_finalize (); free_dominance_info (CDI_DOMINATORS); @@ -223,7 +252,7 @@ struct rtl_opt_pass pass_rtl_loop_done = TV_LOOP, /* tv_id */ 0, /* properties_required */ 0, /* properties_provided */ - 0, /* properties_destroyed */ + PROP_loops, /* properties_destroyed */ 0, /* todo_flags_start */ TODO_verify_flow | TODO_verify_rtl_sharing /* todo_flags_finish */ diff --git a/gcc/omp-low.c b/gcc/omp-low.c index 84986efcdda..ec1a5522d7f 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -1242,7 +1242,7 @@ finalize_task_copyfn (gimple task_stmt) /* Inform the callgraph about the new function. */ DECL_STRUCT_FUNCTION (child_fn)->curr_properties - = cfun->curr_properties; + = cfun->curr_properties & ~PROP_loops; old_fn = current_function_decl; push_cfun (child_cfun); @@ -3562,7 +3562,7 @@ expand_omp_taskreg (struct omp_region *region) /* Inform the callgraph about the new function. */ DECL_STRUCT_FUNCTION (child_fn)->curr_properties - = cfun->curr_properties; + = cfun->curr_properties & ~PROP_loops; cgraph_add_new_function (child_fn, true); /* Fix the callgraph edges for child_cfun. Those for cfun will be diff --git a/gcc/trans-mem.c b/gcc/trans-mem.c index 2badf250650..65f40e69c1b 100644 --- a/gcc/trans-mem.c +++ b/gcc/trans-mem.c @@ -34,6 +34,7 @@ #include "langhooks.h" #include "tree-pretty-print.h" #include "gimple-pretty-print.h" +#include "cfgloop.h" #define PROB_VERY_UNLIKELY (REG_BR_PROB_BASE / 2000 - 1) @@ -1270,6 +1271,12 @@ tm_log_emit_save_or_restores (basic_block entry_block, cond_bb = create_empty_bb (before_bb); code_bb = create_empty_bb (cond_bb); *end_bb = create_empty_bb (code_bb); + if (current_loops && before_bb->loop_father) + { + add_bb_to_loop (cond_bb, before_bb->loop_father); + add_bb_to_loop (code_bb, before_bb->loop_father); + add_bb_to_loop (*end_bb, before_bb->loop_father); + } redirect_edge_pred (fallthru_edge, *end_bb); fallthru_edge->flags = EDGE_FALLTHRU; make_edge (before_bb, cond_bb, old_flags); @@ -2682,6 +2689,8 @@ expand_transaction (struct tm_region *region) basic_block test_bb; test_bb = create_empty_bb (slice_bb); + if (current_loops && slice_bb->loop_father) + add_bb_to_loop (test_bb, slice_bb->loop_father); if (VEC_empty (tree, tm_log_save_addresses)) region->entry_block = test_bb; gsi = gsi_last_bb (test_bb); @@ -2719,6 +2728,8 @@ expand_transaction (struct tm_region *region) basic_block empty_bb; region->entry_block = empty_bb = create_empty_bb (atomic_bb); + if (current_loops && atomic_bb->loop_father) + add_bb_to_loop (empty_bb, atomic_bb->loop_father); e = FALLTHRU_EDGE (atomic_bb); redirect_edge_pred (e, empty_bb); diff --git a/gcc/tree-cfgcleanup.c b/gcc/tree-cfgcleanup.c index 0c8c0852024..d28783b6b98 100644 --- a/gcc/tree-cfgcleanup.c +++ b/gcc/tree-cfgcleanup.c @@ -793,7 +793,6 @@ repair_loop_structures (void) #endif scev_reset (); - loops_state_clear (LOOPS_NEED_FIXUP); timevar_pop (TV_REPAIR_LOOPS); } diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c index 521e2f7f44a..f19dc2cdffb 100644 --- a/gcc/tree-eh.c +++ b/gcc/tree-eh.c @@ -38,6 +38,7 @@ along with GCC; see the file COPYING3. If not see #include "diagnostic-core.h" #include "gimple.h" #include "target.h" +#include "cfgloop.h" /* In some instances a tree and a gimple need to be stored in a same table, i.e. in hash tables. This is a structure to do this. */ @@ -3041,6 +3042,8 @@ lower_resx (basic_block bb, gimple stmt, struct pointer_map_t *mnt_map) gimple_stmt_iterator gsi2; new_bb = create_empty_bb (bb); + if (current_loops) + add_bb_to_loop (new_bb, bb->loop_father); lab = gimple_block_label (new_bb); gsi2 = gsi_start_bb (new_bb); diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index 5d58c5169bb..d61b6b6a023 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -2093,7 +2093,7 @@ initialize_cfun (tree new_fndecl, tree callee_fndecl, gcov_type count) cfun->static_chain_decl = src_cfun->static_chain_decl; cfun->nonlocal_goto_save_area = src_cfun->nonlocal_goto_save_area; cfun->function_end_locus = src_cfun->function_end_locus; - cfun->curr_properties = src_cfun->curr_properties; + cfun->curr_properties = src_cfun->curr_properties & ~PROP_loops; cfun->last_verified = src_cfun->last_verified; cfun->va_list_gpr_size = src_cfun->va_list_gpr_size; cfun->va_list_fpr_size = src_cfun->va_list_fpr_size; diff --git a/gcc/tree-mudflap.c b/gcc/tree-mudflap.c index e4f6ec0b331..cc8b98d1ea4 100644 --- a/gcc/tree-mudflap.c +++ b/gcc/tree-mudflap.c @@ -45,6 +45,8 @@ along with GCC; see the file COPYING3. If not see #include "cgraph.h" #include "gimple.h" +extern void add_bb_to_loop (basic_block, struct loop *); + /* Internal function decls */ @@ -560,6 +562,10 @@ mf_build_check_statement_for (tree base, tree limit, set_immediate_dominator (CDI_DOMINATORS, join_bb, cond_bb); } + /* Update loop info. */ + if (current_loops) + add_bb_to_loop (then_bb, cond_bb->loop_father); + /* Build our local variables. */ mf_elem = make_rename_temp (mf_cache_structptr_type, "__mf_elem"); mf_base = make_rename_temp (mf_uintptr_type, "__mf_base"); diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h index f5cffa3375b..f849a542465 100644 --- a/gcc/tree-pass.h +++ b/gcc/tree-pass.h @@ -239,6 +239,7 @@ struct dump_file_info #define PROP_gimple_lomp (1 << 8) /* lowered OpenMP directives */ #define PROP_cfglayout (1 << 9) /* cfglayout mode on RTL */ #define PROP_gimple_lcx (1 << 10) /* lowered complex */ +#define PROP_loops (1 << 11) /* preserve loop structures */ #define PROP_trees \ (PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh | PROP_gimple_lomp) diff --git a/gcc/tree-ssa-loop.c b/gcc/tree-ssa-loop.c index 91eeb16cec9..a91bf3919ad 100644 --- a/gcc/tree-ssa-loop.c +++ b/gcc/tree-ssa-loop.c @@ -92,7 +92,7 @@ struct gimple_opt_pass pass_tree_loop_init = 0, /* static_pass_number */ TV_TREE_LOOP_INIT, /* tv_id */ PROP_cfg, /* properties_required */ - 0, /* properties_provided */ + PROP_loops, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ 0 /* todo_flags_finish */ diff --git a/gcc/tree-ssa-threadupdate.c b/gcc/tree-ssa-threadupdate.c index 6000a0331c0..4532886ca96 100644 --- a/gcc/tree-ssa-threadupdate.c +++ b/gcc/tree-ssa-threadupdate.c @@ -624,6 +624,7 @@ thread_block (basic_block bb, bool noloop_only) { loop->header = NULL; loop->latch = NULL; + loops_state_set (LOOPS_NEED_FIXUP); } } @@ -969,6 +970,7 @@ thread_through_loop_header (struct loop *loop, bool may_peel_loop_headers) original header. */ loop->header = NULL; loop->latch = NULL; + loops_state_set (LOOPS_NEED_FIXUP); return thread_block (header, false); } |