diff options
author | steven <steven@138bc75d-0d04-0410-961f-82ee72b054a4> | 2009-04-27 17:21:27 +0000 |
---|---|---|
committer | steven <steven@138bc75d-0d04-0410-961f-82ee72b054a4> | 2009-04-27 17:21:27 +0000 |
commit | d743aba2f4aebf422c08b41db532d0c78603a97f (patch) | |
tree | fcb9da5c176fcf8fb2c23a28f80734d495b623b4 | |
parent | fd3f8d709e9ac641e6378a12ddc9ce090169a98d (diff) | |
download | gcc-d743aba2f4aebf422c08b41db532d0c78603a97f.tar.gz |
* dbgcnt.def (cprop1, cprop2, gcse, jump_bypass): Remove
(cprop, hoist, pre, store_motion): New debug counters.
* tree-pass.h (pass_tracer): Move to list of gimple passes, it
is not an RTL pass anymore.
(pass_profiling): Remove extern decl for pass removed in 2005.
(pass_gcse, pass_jump_bypass): Remove.
* final.c (rest_of_clean_state): Set flag_rerun_cse_after_global_opts
to 0 for clean state.
* toplev.h (flag_rerun_cse_after_global_opts): Add extern declaration.
* cse.c (gate_handle_cse_after_global_opts,
rest_of_handle_cse_after_global_opts): New functions.
(pass_cse_after_global_opts): New pass, does local CSE.
* timevar.def (TV_GCSE, TV_CPROP1, TV_CPROP2, TV_BYPASS): Remove.
(TV_CPROP): New timevar.
* gcse.c (flag_rerun_cse_after_global_opts): New global variable.
(run_jump_opt_after_gcse, max_gcse_regno): Remove global vars.
(gcse_main, recompute_all_luids): Remove.
(compute_hash_table_work): Call max_reg_num instead of reading
max_gcse_regno.
(cprop_jump): Don't set run_jump_opt_after_gcse.
(constprop_register): Always allow to alter jumps.
(cprop_insn): Likewise.
(do_local_cprop): Likewise.
(local_cprop_pass): Likewise. Return non-zero if something changed.
(cprop): Remove function, fold interesting bits into one_cprop_pass.
(find_implicit_sets): Add note about missed optimization opportunity.
(one_cprop_pass): Rewrite to be "the" CPROP pass, called from the
pass_rtl_cprop execute function.
Don't bother tracking the pass number, each pass gets its own dumpfile
now anyway.
Always allow to alter jumpsand bypass jumps.
(bypass_block): Don't ignore regno >= max_gcse_regno, find_bypass_set
will just find no suitable set.
(pre_edge_insert): Fix dumping, this function is for PRE only.
(one_pre_gcse_pass): Rewrite to be "the" PRE pass, called from the
pass_rtl_pre execute function.
(hoist_code): Return non-zero if something changed. Keep track of
substitutions and insertions for statistics gathering similar to PRE.
(one_code_hoisting_pass): Rewrite to be "the" code hoisting pass,
called from the pass_rtl_hoist execute function. Show pass statistics.
(compute_store_table): Use max_reg_num directly instead of using the
formerly global max_gcse_regno.
(build_store_vectors): Likewise.
(replace_store_insn): Fix dumping.
(store_motion): Rename to ...
(one_store_motion_pass): ... this. Rewrite to be "the" STORE_MOTION
pass, called from the pass_rtl_store_motion execute function. Keep
track of substitutions and insertions for statistics gathering similar
to PRE.
(bypass_jumps): Remove, fold interesting bits into ...
(one_cprop_pass): ... this. Rewrite to be "the" CPROP pass, called
from the pass_rtl_cprop execute function.
(gate_handle_jump_bypass, rest_of_handle_jump_bypass,
pass_jump_bypass): Remove.
(gate_handle_gcse, rest_of_handle_gcse): Remove.
(gate_rtl_cprop, execute_rtl_cprop, pass_rtl_cprop): New.
(gate_rtl_pre, execute_rtl_pre, pass_rtl_pre): New.
(gate_rtl_hoist, execute_rtl_hoist, pass_rtl_hoist): New.
(gate_rtl_store_motion, execute_rtl_store_motion,
pass_rtl_store_motion): New.
* common.opt: Remove flag_cse_skip_blocks, adjust documentation to
make it clear that -fcse-skip-blocks is a no-op for backward compat.
* passes.c (init_optimization_passes): Remove pass_gcse and
pass_jump_bypass. Schedule cprop, pre, hoist, cprop, store_motion,
and cse_after_global_opts in place of pass_gcse. Schedule cprop
instead of pass_jump_bypass.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@146848 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/ChangeLog | 69 | ||||
-rw-r--r-- | gcc/common.opt | 4 | ||||
-rw-r--r-- | gcc/cse.c | 62 | ||||
-rw-r--r-- | gcc/dbgcnt.def | 8 | ||||
-rw-r--r-- | gcc/final.c | 1 | ||||
-rw-r--r-- | gcc/gcse.c | 807 | ||||
-rw-r--r-- | gcc/passes.c | 9 | ||||
-rw-r--r-- | gcc/timevar.def | 5 | ||||
-rw-r--r-- | gcc/toplev.h | 1 | ||||
-rw-r--r-- | gcc/tree-pass.h | 10 |
10 files changed, 502 insertions, 474 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 8913e38db5d..17520f47292 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,72 @@ +2009-04-27 Steven Bosscher <steven@gcc.gnu.org> + + * dbgcnt.def (cprop1, cprop2, gcse, jump_bypass): Remove + (cprop, hoist, pre, store_motion): New debug counters. + * tree-pass.h (pass_tracer): Move to list of gimple passes, it + is not an RTL pass anymore. + (pass_profiling): Remove extern decl for pass removed in 2005. + (pass_gcse, pass_jump_bypass): Remove. + * final.c (rest_of_clean_state): Set flag_rerun_cse_after_global_opts + to 0 for clean state. + * toplev.h (flag_rerun_cse_after_global_opts): Add extern declaration. + * cse.c (gate_handle_cse_after_global_opts, + rest_of_handle_cse_after_global_opts): New functions. + (pass_cse_after_global_opts): New pass, does local CSE. + * timevar.def (TV_GCSE, TV_CPROP1, TV_CPROP2, TV_BYPASS): Remove. + (TV_CPROP): New timevar. + * gcse.c (flag_rerun_cse_after_global_opts): New global variable. + (run_jump_opt_after_gcse, max_gcse_regno): Remove global vars. + (gcse_main, recompute_all_luids): Remove. + (compute_hash_table_work): Call max_reg_num instead of reading + max_gcse_regno. + (cprop_jump): Don't set run_jump_opt_after_gcse. + (constprop_register): Always allow to alter jumps. + (cprop_insn): Likewise. + (do_local_cprop): Likewise. + (local_cprop_pass): Likewise. Return non-zero if something changed. + (cprop): Remove function, fold interesting bits into one_cprop_pass. + (find_implicit_sets): Add note about missed optimization opportunity. + (one_cprop_pass): Rewrite to be "the" CPROP pass, called from the + pass_rtl_cprop execute function. + Don't bother tracking the pass number, each pass gets its own dumpfile + now anyway. + Always allow to alter jumpsand bypass jumps. + (bypass_block): Don't ignore regno >= max_gcse_regno, find_bypass_set + will just find no suitable set. + (pre_edge_insert): Fix dumping, this function is for PRE only. + (one_pre_gcse_pass): Rewrite to be "the" PRE pass, called from the + pass_rtl_pre execute function. + (hoist_code): Return non-zero if something changed. Keep track of + substitutions and insertions for statistics gathering similar to PRE. + (one_code_hoisting_pass): Rewrite to be "the" code hoisting pass, + called from the pass_rtl_hoist execute function. Show pass statistics. + (compute_store_table): Use max_reg_num directly instead of using the + formerly global max_gcse_regno. + (build_store_vectors): Likewise. + (replace_store_insn): Fix dumping. + (store_motion): Rename to ... + (one_store_motion_pass): ... this. Rewrite to be "the" STORE_MOTION + pass, called from the pass_rtl_store_motion execute function. Keep + track of substitutions and insertions for statistics gathering similar + to PRE. + (bypass_jumps): Remove, fold interesting bits into ... + (one_cprop_pass): ... this. Rewrite to be "the" CPROP pass, called + from the pass_rtl_cprop execute function. + (gate_handle_jump_bypass, rest_of_handle_jump_bypass, + pass_jump_bypass): Remove. + (gate_handle_gcse, rest_of_handle_gcse): Remove. + (gate_rtl_cprop, execute_rtl_cprop, pass_rtl_cprop): New. + (gate_rtl_pre, execute_rtl_pre, pass_rtl_pre): New. + (gate_rtl_hoist, execute_rtl_hoist, pass_rtl_hoist): New. + (gate_rtl_store_motion, execute_rtl_store_motion, + pass_rtl_store_motion): New. + * common.opt: Remove flag_cse_skip_blocks, adjust documentation to + make it clear that -fcse-skip-blocks is a no-op for backward compat. + * passes.c (init_optimization_passes): Remove pass_gcse and + pass_jump_bypass. Schedule cprop, pre, hoist, cprop, store_motion, + and cse_after_global_opts in place of pass_gcse. Schedule cprop + instead of pass_jump_bypass. + 2009-04-27 Richard Guenther <rguenther@suse.de> PR middle-end/39928 diff --git a/gcc/common.opt b/gcc/common.opt index c0f6b9e6d09..3e1b80a7215 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -397,8 +397,8 @@ Common Report Var(flag_cse_follow_jumps) Optimization When running CSE, follow jumps to their targets fcse-skip-blocks -Common Report Var(flag_cse_skip_blocks) Optimization -When running CSE, follow conditional jumps +Common +Does nothing. Preserved for backward compatibility. fcx-limited-range Common Report Var(flag_cx_limited_range) Optimization diff --git a/gcc/cse.c b/gcc/cse.c index 3f36a1c8371..2b814937535 100644 --- a/gcc/cse.c +++ b/gcc/cse.c @@ -6997,3 +6997,65 @@ struct rtl_opt_pass pass_cse2 = TODO_verify_flow /* todo_flags_finish */ } }; + +static bool +gate_handle_cse_after_global_opts (void) +{ + return optimize > 0 && flag_rerun_cse_after_global_opts; +} + +/* Run second CSE pass after loop optimizations. */ +static unsigned int +rest_of_handle_cse_after_global_opts (void) +{ + int save_cfj; + int tem; + + /* We only want to do local CSE, so don't follow jumps. */ + save_cfj = flag_cse_follow_jumps; + flag_cse_follow_jumps = 0; + + rebuild_jump_labels (get_insns ()); + tem = cse_main (get_insns (), max_reg_num ()); + purge_all_dead_edges (); + delete_trivially_dead_insns (get_insns (), max_reg_num ()); + + cse_not_expected = !flag_rerun_cse_after_loop; + + /* If cse altered any jumps, rerun jump opts to clean things up. */ + if (tem == 2) + { + timevar_push (TV_JUMP); + rebuild_jump_labels (get_insns ()); + cleanup_cfg (0); + timevar_pop (TV_JUMP); + } + else if (tem == 1) + cleanup_cfg (0); + + flag_cse_follow_jumps = save_cfj; + return 0; +} + +struct rtl_opt_pass pass_cse_after_global_opts = +{ + { + RTL_PASS, + "cse_local", /* name */ + gate_handle_cse_after_global_opts, /* gate */ + rest_of_handle_cse_after_global_opts, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_CSE, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_df_finish | TODO_verify_rtl_sharing | + TODO_dump_func | + TODO_ggc_collect | + TODO_verify_flow /* todo_flags_finish */ + } +}; + diff --git a/gcc/dbgcnt.def b/gcc/dbgcnt.def index 5a2f8f0c505..82dd988a86c 100644 --- a/gcc/dbgcnt.def +++ b/gcc/dbgcnt.def @@ -145,8 +145,7 @@ DEBUG_COUNTER (auto_inc_dec) DEBUG_COUNTER (ccp) DEBUG_COUNTER (cfg_cleanup) DEBUG_COUNTER (cse2_move2add) -DEBUG_COUNTER (cprop1) -DEBUG_COUNTER (cprop2) +DEBUG_COUNTER (cprop) DEBUG_COUNTER (dce) DEBUG_COUNTER (dce_fast) DEBUG_COUNTER (dce_ud) @@ -155,17 +154,17 @@ DEBUG_COUNTER (df_byte_scan) DEBUG_COUNTER (dse) DEBUG_COUNTER (dse1) DEBUG_COUNTER (dse2) -DEBUG_COUNTER (gcse) DEBUG_COUNTER (gcse2_delete) DEBUG_COUNTER (global_alloc_at_func) DEBUG_COUNTER (global_alloc_at_reg) +DEBUG_COUNTER (hoist) DEBUG_COUNTER (ia64_sched2) DEBUG_COUNTER (if_conversion) DEBUG_COUNTER (if_after_combine) DEBUG_COUNTER (if_after_reload) -DEBUG_COUNTER (jump_bypass) DEBUG_COUNTER (local_alloc_for_sched) DEBUG_COUNTER (postreload_cse) +DEBUG_COUNTER (pre) DEBUG_COUNTER (pre_insn) DEBUG_COUNTER (treepre_insert) DEBUG_COUNTER (sched2_func) @@ -177,5 +176,6 @@ DEBUG_COUNTER (sel_sched_cnt) DEBUG_COUNTER (sel_sched_region_cnt) DEBUG_COUNTER (sel_sched_insn_cnt) DEBUG_COUNTER (sms_sched_loop) +DEBUG_COUNTER (store_motion) DEBUG_COUNTER (split_for_sched2) DEBUG_COUNTER (tail_call) diff --git a/gcc/final.c b/gcc/final.c index 621bc28bcb1..551b3a0e8b0 100644 --- a/gcc/final.c +++ b/gcc/final.c @@ -4298,6 +4298,7 @@ rest_of_clean_state (void) sdbout_types (NULL_TREE); #endif + flag_rerun_cse_after_global_opts = 0; reload_completed = 0; epilogue_completed = 0; #ifdef STACK_REGS diff --git a/gcc/gcse.c b/gcc/gcse.c index 6bf1d502bbe..c7b4b8fd1f9 100644 --- a/gcc/gcse.c +++ b/gcc/gcse.c @@ -280,13 +280,8 @@ along with GCC; see the file COPYING3. If not see /* GCSE global vars. */ -/* Note whether or not we should run jump optimization after gcse. We - want to do this for two cases. - - * If we changed any jumps via cprop. - - * If we added any labels via edge splitting. */ -static int run_jump_opt_after_gcse; +/* Set to non-zero if CSE should run after all GCSE optimizations are done. */ +int flag_rerun_cse_after_global_opts; /* An obstack for our working variables. */ static struct obstack gcse_obstack; @@ -370,11 +365,6 @@ static struct hash_table expr_hash_table; /* Copy propagation hash table. */ static struct hash_table set_hash_table; -/* Maximum register number in function prior to doing gcse + 1. - Registers created during this pass have regno >= max_gcse_regno. - This is named with "gcse" to not collide with global of same name. */ -static unsigned int max_gcse_regno; - /* This is a list of expressions which are MEMs and will be used by load or store motion. Load motion tracks MEMs which aren't killed by @@ -450,7 +440,6 @@ static int global_copy_prop_count; static sbitmap *ae_kill, *ae_gen; static void compute_can_copy (void); -static void recompute_all_luids (void); static void *gmalloc (size_t) ATTRIBUTE_MALLOC; static void *gcalloc (size_t, size_t) ATTRIBUTE_MALLOC; static void *gcse_alloc (unsigned long); @@ -502,11 +491,10 @@ static int cprop_jump (basic_block, rtx, rtx, rtx, rtx); static void mems_conflict_for_gcse_p (rtx, const_rtx, void *); static int load_killed_in_block_p (const_basic_block, int, const_rtx, int); static void canon_list_insert (rtx, const_rtx, void *); -static int cprop_insn (rtx, int); -static int cprop (int); +static int cprop_insn (rtx); static void find_implicit_sets (void); -static int one_cprop_pass (int, bool, bool); -static bool constprop_register (rtx, rtx, rtx, bool); +static int one_cprop_pass (void); +static bool constprop_register (rtx, rtx, rtx); static struct expr *find_bypass_set (int, int); static bool reg_killed_on_edge (const_rtx, const_edge); static int bypass_block (basic_block, rtx, rtx); @@ -521,14 +509,14 @@ static void pre_insert_copy_insn (struct expr *, rtx); static void pre_insert_copies (void); static int pre_delete (void); static int pre_gcse (void); -static int one_pre_gcse_pass (int); +static int one_pre_gcse_pass (void); static void add_label_notes (rtx, rtx); static void alloc_code_hoist_mem (int, int); static void free_code_hoist_mem (void); static void compute_code_hoist_vbeinout (void); static void compute_code_hoist_data (void); static int hoist_expr_reaches_here_p (basic_block, int, basic_block, char *); -static void hoist_code (void); +static int hoist_code (void); static int one_code_hoisting_pass (void); static rtx process_insert_insn (struct expr *); static int pre_edge_insert (struct edge_list *, struct expr **); @@ -566,14 +554,14 @@ static void remove_reachable_equiv_notes (basic_block, struct ls_expr *); static void replace_store_insn (rtx, rtx, basic_block, struct ls_expr *); static void delete_store (struct ls_expr *, basic_block); static void free_store_memory (void); -static void store_motion (void); +static int one_store_motion_pass (void); static void free_insn_expr_list_list (rtx *); static void clear_modify_mem_tables (void); static void free_modify_mem_tables (void); static rtx gcse_emit_move_after (rtx, rtx, rtx); static void local_cprop_find_used_regs (rtx *, void *); -static bool do_local_cprop (rtx, rtx, bool); -static void local_cprop_pass (bool); +static bool do_local_cprop (rtx, rtx); +static int local_cprop_pass (void); static bool is_too_expensive (const char *); #define GNEW(T) ((T *) gmalloc (sizeof (T))) @@ -588,155 +576,6 @@ static bool is_too_expensive (const char *); #define GOBNEW(T) ((T *) gcse_alloc (sizeof (T))) #define GOBNEWVAR(T, S) ((T *) gcse_alloc ((S))) - -/* Entry point for global common subexpression elimination. - F is the first instruction in the function. Return nonzero if a - change is mode. */ - -static int -gcse_main (rtx f ATTRIBUTE_UNUSED) -{ - int changed; - /* Point to release obstack data from for each pass. */ - char *gcse_obstack_bottom; - - /* We do not construct an accurate cfg in functions which call - setjmp, so just punt to be safe. */ - if (cfun->calls_setjmp) - return 0; - - /* Assume that we do not need to run jump optimizations after gcse. */ - run_jump_opt_after_gcse = 0; - - /* Identify the basic block information for this function, including - successors and predecessors. */ - max_gcse_regno = max_reg_num (); - - df_note_add_problem (); - df_analyze (); - - if (dump_file) - dump_flow_info (dump_file, dump_flags); - - /* Return if there's nothing to do, or it is too expensive. */ - if (n_basic_blocks <= NUM_FIXED_BLOCKS + 1 - || is_too_expensive (_("GCSE disabled"))) - return 0; - - gcc_obstack_init (&gcse_obstack); - bytes_used = 0; - - /* We need alias. */ - init_alias_analysis (); - - gcse_obstack_bottom = GOBNEWVAR (char, 1); - changed = 0; - - if (dump_file) - fprintf (dump_file, "GCSE pass\n\n"); - - max_gcse_regno = max_reg_num (); - - alloc_gcse_mem (); - - /* Don't allow constant propagation to modify jumps - during this pass. */ - if (dbg_cnt (cprop1)) - { - timevar_push (TV_CPROP1); - changed = one_cprop_pass (1, false, false); - if (changed) - recompute_all_luids (); - timevar_pop (TV_CPROP1); - } - - if (optimize_function_for_speed_p (cfun)) - { - timevar_push (TV_PRE); - changed |= one_pre_gcse_pass (1); - /* We may have just created new basic blocks. Release and - recompute various things which are sized on the number of - basic blocks. - ??? There would be no need for this if we used a block - based Lazy Code Motion variant, with all (or selected) - edges split before running the pass. That would also - help find_implicit_sets for cprop. FIXME. */ - if (changed) - { - free_modify_mem_tables (); - modify_mem_list = GCNEWVEC (rtx, last_basic_block); - canon_modify_mem_list = GCNEWVEC (rtx, last_basic_block); - } - - df_analyze (); - run_jump_opt_after_gcse = 1; - timevar_pop (TV_PRE); - } - else - { - /* This function is being optimized for code size. - It does not make sense to run code hoisting unless we are optimizing - for code size -- it rarely makes programs faster, and can make - them bigger if we did partial redundancy elimination (when optimizing - for space, we don't run the partial redundancy algorithms). */ - timevar_push (TV_HOIST); - max_gcse_regno = max_reg_num (); - alloc_gcse_mem (); - one_code_hoisting_pass (); - timevar_pop (TV_HOIST); - } - - free_gcse_mem (); - - if (dump_file) - { - fprintf (dump_file, "\n"); - fflush (dump_file); - } - - obstack_free (&gcse_obstack, gcse_obstack_bottom); - - /* Do the second const/copy propagation pass, including cprop into - conditional jumps. */ - if (dbg_cnt (cprop2)) - { - max_gcse_regno = max_reg_num (); - alloc_gcse_mem (); - - /* This time, go ahead and allow cprop to alter jumps. */ - timevar_push (TV_CPROP2); - changed = one_cprop_pass (2, true, true); - if (changed) - recompute_all_luids (); - timevar_pop (TV_CPROP2); - free_gcse_mem (); - } - - if (dump_file) - { - fprintf (dump_file, "GCSE of %s: %d basic blocks, ", - current_function_name (), n_basic_blocks); - fprintf (dump_file, "pass 1, %d bytes\n\n", bytes_used); - } - - obstack_free (&gcse_obstack, NULL); - - /* We are finished with alias. - ??? Actually we recompute alias in store_motion. */ - end_alias_analysis (); - - /* Run store motion. */ - if (optimize_function_for_speed_p (cfun) && flag_gcse_sm) - { - timevar_push (TV_LSM); - store_motion (); - timevar_pop (TV_LSM); - } - - /* Record where pseudo-registers are set. */ - return run_jump_opt_after_gcse; -} - /* Misc. utilities. */ /* Nonzero for each mode that supports (set (reg) (reg)). @@ -790,19 +629,6 @@ can_copy_p (enum machine_mode mode) return can_copy[mode] != 0; } -/* Recompute the DF LUIDs for all basic blocks. If a sub-pass in this - file changes something, we have to recompute them for the next pass. - FIXME: If we would track which basic blocks we touch, we could - update LUIDs in only those basic blocks. */ - -static void -recompute_all_luids (void) -{ - basic_block bb; - FOR_EACH_BB (bb) - df_recompute_luids (bb); -} - /* Cover function to xmalloc to record bytes allocated. */ @@ -1447,11 +1273,10 @@ insert_set_in_table (rtx x, rtx insn, struct hash_table *table) /* First occurrence of this expression in this basic block. */ cur_occr = GOBNEW (struct occr); bytes_used += sizeof (struct occr); - - cur_occr->insn = insn; - cur_occr->next = cur_expr->avail_occr; - cur_occr->deleted_p = 0; - cur_expr->avail_occr = cur_occr; + cur_occr->insn = insn; + cur_occr->next = cur_expr->avail_occr; + cur_occr->deleted_p = 0; + cur_expr->avail_occr = cur_occr; } } @@ -1839,14 +1664,14 @@ record_last_set_info (rtx dest, const_rtx setter ATTRIBUTE_UNUSED, void *data) static void compute_hash_table_work (struct hash_table *table) { - unsigned int i; + int i; /* re-Cache any INSN_LIST nodes we have allocated. */ clear_modify_mem_tables (); /* Some working arrays used to track first and last set in each block. */ - reg_avail_info = GNEWVEC (struct reg_avail_info, max_gcse_regno); + reg_avail_info = GNEWVEC (struct reg_avail_info, max_reg_num ()); - for (i = 0; i < max_gcse_regno; ++i) + for (i = 0; i < max_reg_num (); ++i) reg_avail_info[i].last_bb = NULL; FOR_EACH_BB (current_bb) @@ -2631,8 +2456,6 @@ cprop_jump (basic_block bb, rtx setcc, rtx jump, rtx from, rtx src) delete_insn (setcc); #endif - run_jump_opt_after_gcse = 1; - global_const_prop_count++; if (dump_file != NULL) { @@ -2666,14 +2489,13 @@ cprop_jump (basic_block bb, rtx setcc, rtx jump, rtx from, rtx src) } static bool -constprop_register (rtx insn, rtx from, rtx to, bool alter_jumps) +constprop_register (rtx insn, rtx from, rtx to) { rtx sset; /* Check for reg or cc0 setting instructions followed by conditional branch instructions first. */ - if (alter_jumps - && (sset = single_set (insn)) != NULL + if ((sset = single_set (insn)) != NULL && NEXT_INSN (insn) && any_condjump_p (NEXT_INSN (insn)) && onlyjump_p (NEXT_INSN (insn))) { @@ -2694,7 +2516,7 @@ constprop_register (rtx insn, rtx from, rtx to, bool alter_jumps) Right now the insn in question must look like (set (pc) (if_then_else ...)) */ - else if (alter_jumps && any_condjump_p (insn) && onlyjump_p (insn)) + else if (any_condjump_p (insn) && onlyjump_p (insn)) return cprop_jump (BLOCK_FOR_INSN (insn), NULL, insn, from, to); return 0; } @@ -2703,7 +2525,7 @@ constprop_register (rtx insn, rtx from, rtx to, bool alter_jumps) The result is nonzero if a change was made. */ static int -cprop_insn (rtx insn, int alter_jumps) +cprop_insn (rtx insn) { struct reg_use *reg_used; int changed = 0; @@ -2728,11 +2550,6 @@ cprop_insn (rtx insn, int alter_jumps) rtx pat, src; struct expr *set; - /* Ignore registers created by GCSE. - We do this because ... */ - if (regno >= max_gcse_regno) - continue; - /* If the register has already been set in this block, there's nothing we can do. */ if (! oprs_not_set_p (reg_used->reg_rtx, insn)) @@ -2753,7 +2570,7 @@ cprop_insn (rtx insn, int alter_jumps) /* Constant propagation. */ if (gcse_constant_p (src)) { - if (constprop_register (insn, reg_used->reg_rtx, src, alter_jumps)) + if (constprop_register (insn, reg_used->reg_rtx, src)) { changed = 1; global_const_prop_count++; @@ -2840,11 +2657,10 @@ local_cprop_find_used_regs (rtx *xptr, void *data) find_used_regs (xptr, data); } -/* Try to perform local const/copy propagation on X in INSN. - If ALTER_JUMPS is false, changing jump insns is not allowed. */ +/* Try to perform local const/copy propagation on X in INSN. */ static bool -do_local_cprop (rtx x, rtx insn, bool alter_jumps) +do_local_cprop (rtx x, rtx insn) { rtx newreg = NULL, newcnst = NULL; @@ -2877,7 +2693,7 @@ do_local_cprop (rtx x, rtx insn, bool alter_jumps) || ! MEM_P (XEXP (note, 0)))) newreg = this_rtx; } - if (newcnst && constprop_register (insn, x, newcnst, alter_jumps)) + if (newcnst && constprop_register (insn, x, newcnst)) { if (dump_file != NULL) { @@ -2907,12 +2723,10 @@ do_local_cprop (rtx x, rtx insn, bool alter_jumps) return false; } -/* Do local const/copy propagation (i.e. within each basic block). - If ALTER_JUMPS is true, allow propagating into jump insns, which - could modify the CFG. */ +/* Do local const/copy propagation (i.e. within each basic block). */ -static void -local_cprop_pass (bool alter_jumps) +static int +local_cprop_pass (void) { basic_block bb; rtx insn; @@ -2938,7 +2752,7 @@ local_cprop_pass (bool alter_jumps) for (reg_used = ®_use_table[0]; reg_use_count > 0; reg_used++, reg_use_count--) { - if (do_local_cprop (reg_used->reg_rtx, insn, alter_jumps)) + if (do_local_cprop (reg_used->reg_rtx, insn)) { changed = true; break; @@ -2958,52 +2772,6 @@ local_cprop_pass (bool alter_jumps) cselib_finish (); - /* Global analysis may get into infinite loops for unreachable blocks. */ - if (changed && alter_jumps) - delete_unreachable_blocks (); -} - -/* Forward propagate copies. This includes copies and constants. Return - nonzero if a change was made. */ - -static int -cprop (int alter_jumps) -{ - int changed; - basic_block bb; - rtx insn; - - /* Note we start at block 1. */ - if (ENTRY_BLOCK_PTR->next_bb == EXIT_BLOCK_PTR) - { - if (dump_file != NULL) - fprintf (dump_file, "\n"); - return 0; - } - - changed = 0; - FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR->next_bb->next_bb, EXIT_BLOCK_PTR, next_bb) - { - /* Reset tables used to keep track of what's still valid [since the - start of the block]. */ - reset_opr_set_tables (); - - FOR_BB_INSNS (bb, insn) - if (INSN_P (insn)) - { - changed |= cprop_insn (insn, alter_jumps); - - /* Keep track of everything modified by this insn. */ - /* ??? Need to be careful w.r.t. mods done to INSN. Don't - call mark_oprs_set if we turned the insn into a NOTE. */ - if (! NOTE_P (insn)) - mark_oprs_set (insn); - } - } - - if (dump_file != NULL) - fprintf (dump_file, "\n"); - return changed; } @@ -3060,7 +2828,12 @@ implicit_set_cond_p (const_rtx cond) following "if (x == 2)", the then branch may be optimized as though the conditional performed an "explicit set", in this example, "x = 2". This function records the set patterns that are implicit at the start of each - basic block. */ + basic block. + + FIXME: This would be more effective if critical edges are pre-split. As + it is now, we can't record implicit sets for blocks that have + critical successor edges. This results in missed optimizations + and in more (unnecessary) work in cfgcleanup.c:thread_jump(). */ static void find_implicit_sets (void) @@ -3085,7 +2858,9 @@ find_implicit_sets (void) dest = GET_CODE (cond) == EQ ? BRANCH_EDGE (bb)->dest : FALLTHRU_EDGE (bb)->dest; - if (dest && single_pred_p (dest) + if (dest + /* Record nothing for a critical edge. */ + && single_pred_p (dest) && dest != EXIT_BLOCK_PTR) { new_rtx = gen_rtx_SET (VOIDmode, XEXP (cond, 0), @@ -3106,63 +2881,6 @@ find_implicit_sets (void) fprintf (dump_file, "Found %d implicit sets\n", count); } -/* Perform one copy/constant propagation pass. - PASS is the pass count. If CPROP_JUMPS is true, perform constant - propagation into conditional jumps. If BYPASS_JUMPS is true, - perform conditional jump bypassing optimizations. */ - -static int -one_cprop_pass (int pass, bool cprop_jumps, bool bypass_jumps) -{ - int changed = 0; - - global_const_prop_count = local_const_prop_count = 0; - global_copy_prop_count = local_copy_prop_count = 0; - - if (cprop_jumps) - local_cprop_pass (cprop_jumps); - - /* Determine implicit sets. */ - implicit_sets = XCNEWVEC (rtx, last_basic_block); - find_implicit_sets (); - - alloc_hash_table (get_max_uid (), &set_hash_table, 1); - compute_hash_table (&set_hash_table); - - /* Free implicit_sets before peak usage. */ - free (implicit_sets); - implicit_sets = NULL; - - if (dump_file) - dump_hash_table (dump_file, "SET", &set_hash_table); - if (set_hash_table.n_elems > 0) - { - alloc_cprop_mem (last_basic_block, set_hash_table.n_elems); - compute_cprop_data (); - changed = cprop (cprop_jumps); - if (bypass_jumps) - changed |= bypass_conditional_jumps (); - free_cprop_mem (); - } - - free_hash_table (&set_hash_table); - - if (dump_file) - { - fprintf (dump_file, "CPROP of %s, pass %d: %d bytes needed, ", - current_function_name (), pass, bytes_used); - fprintf (dump_file, "%d local const props, %d local copy props, ", - local_const_prop_count, local_copy_prop_count); - fprintf (dump_file, "%d global const props, %d global copy props\n\n", - global_const_prop_count, global_copy_prop_count); - } - /* Global analysis may get into infinite loops for unreachable blocks. */ - if (changed && cprop_jumps) - delete_unreachable_blocks (); - - return changed; -} - /* Bypass conditional jumps. */ /* The value of last_basic_block at the beginning of the jump_bypass @@ -3302,9 +3020,6 @@ bypass_block (basic_block bb, rtx setcc, rtx jump) struct expr *set; rtx src, new_rtx; - if (regno >= max_gcse_regno) - continue; - set = find_bypass_set (regno, e->src->index); if (! set) @@ -3888,7 +3603,7 @@ pre_edge_insert (struct edge_list *edge_list, struct expr **index_map) if (dump_file) { - fprintf (dump_file, "PRE/HOIST: edge (%d,%d), ", + fprintf (dump_file, "PRE: edge (%d,%d), ", bb->index, INDEX_EDGE_SUCC_BB (edge_list, e)->index); fprintf (dump_file, "copy expression %d\n", @@ -4232,13 +3947,25 @@ pre_gcse (void) Return nonzero if a change was made. */ static int -one_pre_gcse_pass (int pass) +one_pre_gcse_pass (void) { int changed = 0; gcse_subst_count = 0; gcse_create_count = 0; + /* Return if there's nothing to do, or it is too expensive. */ + if (n_basic_blocks <= NUM_FIXED_BLOCKS + 1 + || is_too_expensive (_("PRE disabled"))) + return 0; + + /* We need alias. */ + init_alias_analysis (); + + bytes_used = 0; + gcc_obstack_init (&gcse_obstack); + alloc_gcse_mem (); + alloc_hash_table (get_max_uid (), &expr_hash_table, 0); add_noreturn_fake_exit_edges (); if (flag_gcse_lm) @@ -4262,10 +3989,16 @@ one_pre_gcse_pass (int pass) remove_fake_exit_edges (); free_hash_table (&expr_hash_table); + free_gcse_mem (); + obstack_free (&gcse_obstack, NULL); + + /* We are finished with alias. */ + end_alias_analysis (); + if (dump_file) { - fprintf (dump_file, "\nPRE GCSE of %s, pass %d: %d bytes needed, ", - current_function_name (), pass, bytes_used); + fprintf (dump_file, "PRE GCSE of %s, %d basic blocks, %d bytes needed, ", + current_function_name (), n_basic_blocks, bytes_used); fprintf (dump_file, "%d substs, %d insns created\n", gcse_subst_count, gcse_create_count); } @@ -4530,7 +4263,7 @@ hoist_expr_reaches_here_p (basic_block expr_bb, int expr_index, basic_block bb, /* Actually perform code hoisting. */ -static void +static int hoist_code (void) { basic_block bb, dominated; @@ -4538,6 +4271,7 @@ hoist_code (void) unsigned int i,j; struct expr **index_map; struct expr *expr; + int changed = 0; sbitmap_vector_zero (hoist_exprs, last_basic_block); @@ -4669,6 +4403,9 @@ hoist_code (void) gcse_emit_move_after (expr->reaching_reg, SET_DEST (set), insn); delete_insn (insn); occr->deleted_p = 1; + changed = 1; + gcse_subst_count++; + if (!insn_inserted_p) { insert_insn_end_basic_block (index_map[i], bb, 0); @@ -4682,6 +4419,8 @@ hoist_code (void) } free (index_map); + + return changed; } /* Top level routine to perform one code hoisting (aka unification) pass @@ -4693,6 +4432,21 @@ one_code_hoisting_pass (void) { int changed = 0; + gcse_subst_count = 0; + gcse_create_count = 0; + + /* Return if there's nothing to do, or it is too expensive. */ + if (n_basic_blocks <= NUM_FIXED_BLOCKS + 1 + || is_too_expensive (_("GCSE disabled"))) + return 0; + + /* We need alias. */ + init_alias_analysis (); + + bytes_used = 0; + gcc_obstack_init (&gcse_obstack); + alloc_gcse_mem (); + alloc_hash_table (get_max_uid (), &expr_hash_table, 0); compute_hash_table (&expr_hash_table); if (dump_file) @@ -4702,11 +4456,24 @@ one_code_hoisting_pass (void) { alloc_code_hoist_mem (last_basic_block, expr_hash_table.n_elems); compute_code_hoist_data (); - hoist_code (); + changed = hoist_code (); free_code_hoist_mem (); } free_hash_table (&expr_hash_table); + free_gcse_mem (); + obstack_free (&gcse_obstack, NULL); + + /* We are finished with alias. */ + end_alias_analysis (); + + if (dump_file) + { + fprintf (dump_file, "HOIST of %s, %d basic blocks, %d bytes needed, ", + current_function_name (), n_basic_blocks, bytes_used); + fprintf (dump_file, "%d substs, %d insns created\n", + gcse_subst_count, gcse_create_count); + } return changed; } @@ -5441,8 +5208,7 @@ compute_store_table (void) rtx insn, pat, tmp; int *last_set_in, *already_set; struct ls_expr * ptr, **prev_next_ptr_ptr; - - max_gcse_regno = max_reg_num (); + unsigned int max_gcse_regno = max_reg_num (); pre_ldst_mems = 0; pre_ldst_table = htab_create (13, pre_ldst_expr_hash, @@ -5762,6 +5528,7 @@ build_store_vectors (void) int *regs_set_in_block; rtx insn, st; struct ls_expr * ptr; + unsigned int max_gcse_regno = max_reg_num (); /* Build the gen_vector. This is any store in the table which is not killed by aliasing later in its block. */ @@ -6060,7 +5827,7 @@ replace_store_insn (rtx reg, rtx del, basic_block bb, struct ls_expr *smexpr) fprintf (dump_file, "STORE_MOTION delete insn in BB %d:\n ", bb->index); print_inline_rtx (dump_file, del, 6); - fprintf (dump_file, "\nSTORE MOTION replaced with insn:\n "); + fprintf (dump_file, "\nSTORE_MOTION replaced with insn:\n "); print_inline_rtx (dump_file, insn, 6); fprintf (dump_file, "\n"); } @@ -6142,21 +5909,19 @@ free_store_memory (void) } /* Perform store motion. Much like gcse, except we move expressions the - other way by looking at the flowgraph in reverse. */ + other way by looking at the flowgraph in reverse. + Return non-zero if transformations are performed by the pass. */ -static void -store_motion (void) +static int +one_store_motion_pass (void) { basic_block bb; int x; struct ls_expr * ptr; int update_flow = 0; - if (dump_file) - { - fprintf (dump_file, "before store motion\n"); - print_rtl (dump_file, get_insns ()); - } + gcse_subst_count = 0; + gcse_create_count = 0; init_alias_analysis (); @@ -6167,7 +5932,7 @@ store_motion (void) htab_delete (pre_ldst_table); pre_ldst_table = NULL; end_alias_analysis (); - return; + return 0; } /* Now compute kill & transp vectors. */ @@ -6203,11 +5968,17 @@ store_motion (void) FOR_EACH_BB (bb) if (TEST_BIT (pre_delete_map[bb->index], ptr->index)) - delete_store (ptr, bb); + { + delete_store (ptr, bb); + gcse_subst_count++; + } for (x = 0; x < NUM_EDGES (edge_list); x++) if (TEST_BIT (pre_insert_map[x], ptr->index)) - update_flow |= insert_store (ptr, INDEX_EDGE (edge_list, x)); + { + update_flow |= insert_store (ptr, INDEX_EDGE (edge_list, x)); + gcse_create_count++; + } } if (update_flow) @@ -6217,59 +5988,19 @@ store_motion (void) free_edge_list (edge_list); remove_fake_exit_edges (); end_alias_analysis (); -} - - -/* Entry point for jump bypassing optimization pass. */ - -static int -bypass_jumps (void) -{ - int changed; - - /* We do not construct an accurate cfg in functions which call - setjmp, so just punt to be safe. */ - if (cfun->calls_setjmp) - return 0; - - /* Identify the basic block information for this function, including - successors and predecessors. */ - max_gcse_regno = max_reg_num (); - - if (dump_file) - dump_flow_info (dump_file, dump_flags); - - /* Return if there's nothing to do, or it is too expensive. */ - if (n_basic_blocks <= NUM_FIXED_BLOCKS + 1 - || is_too_expensive (_ ("jump bypassing disabled"))) - return 0; - - gcc_obstack_init (&gcse_obstack); - bytes_used = 0; - - /* We need alias. */ - init_alias_analysis (); - - max_gcse_regno = max_reg_num (); - alloc_gcse_mem (); - changed = one_cprop_pass (3, true, true); - free_gcse_mem (); if (dump_file) { - fprintf (dump_file, "BYPASS of %s: %d basic blocks, ", + fprintf (dump_file, "STORE_MOTION of %s, %d basic blocks, ", current_function_name (), n_basic_blocks); - fprintf (dump_file, "%d bytes\n\n", bytes_used); + fprintf (dump_file, "%d substs, %d insns created\n", + gcse_subst_count, gcse_create_count); } - obstack_free (&gcse_obstack, NULL); - - /* We are finished with alias. */ - end_alias_analysis (); - - return changed; + return (gcse_subst_count > 0 || gcse_create_count > 0); } + /* Return true if the graph is too expensive to optimize. PASS is the optimization about to be performed. */ @@ -6309,110 +6040,250 @@ is_too_expensive (const char *pass) return false; } + +/* Main function for the CPROP pass. */ + +static int +one_cprop_pass (void) +{ + int changed = 0; + + /* Return if there's nothing to do, or it is too expensive. */ + if (n_basic_blocks <= NUM_FIXED_BLOCKS + 1 + || is_too_expensive (_ ("const/copy propagation disabled"))) + return 0; + + global_const_prop_count = local_const_prop_count = 0; + global_copy_prop_count = local_copy_prop_count = 0; + + bytes_used = 0; + gcc_obstack_init (&gcse_obstack); + alloc_gcse_mem (); + + /* Do a local const/copy propagation pass first. The global pass + only handles global opportunities. + If the local pass changes something, remove any unreachable blocks + because the CPROP global dataflow analysis may get into infinite + loops for CFGs with unreachable blocks. + + FIXME: This local pass should not be necessary after CSE (but for + some reason it still is). It is also (proven) not necessary + to run the local pass right after FWPWOP. + + FIXME: The global analysis would not get into infinite loops if it + would use the DF solver (via df_simple_dataflow) instead of + the solver implemented in this file. */ + if (local_cprop_pass ()) + { + delete_unreachable_blocks (); + df_analyze (); + } + + /* Determine implicit sets. */ + implicit_sets = XCNEWVEC (rtx, last_basic_block); + find_implicit_sets (); + + alloc_hash_table (get_max_uid (), &set_hash_table, 1); + compute_hash_table (&set_hash_table); + + /* Free implicit_sets before peak usage. */ + free (implicit_sets); + implicit_sets = NULL; + + if (dump_file) + dump_hash_table (dump_file, "SET", &set_hash_table); + if (set_hash_table.n_elems > 0) + { + basic_block bb; + rtx insn; + + alloc_cprop_mem (last_basic_block, set_hash_table.n_elems); + compute_cprop_data (); + + FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR->next_bb->next_bb, EXIT_BLOCK_PTR, next_bb) + { + /* Reset tables used to keep track of what's still valid [since + the start of the block]. */ + reset_opr_set_tables (); + + FOR_BB_INSNS (bb, insn) + if (INSN_P (insn)) + { + changed |= cprop_insn (insn); + + /* Keep track of everything modified by this insn. */ + /* ??? Need to be careful w.r.t. mods done to INSN. + Don't call mark_oprs_set if we turned the + insn into a NOTE. */ + if (! NOTE_P (insn)) + mark_oprs_set (insn); + } + } + + changed |= bypass_conditional_jumps (); + free_cprop_mem (); + } + + free_hash_table (&set_hash_table); + free_gcse_mem (); + obstack_free (&gcse_obstack, NULL); + + if (dump_file) + { + fprintf (dump_file, "CPROP of %s, %d basic blocks, %d bytes needed, ", + current_function_name (), n_basic_blocks, bytes_used); + fprintf (dump_file, "%d local const props, %d local copy props, ", + local_const_prop_count, local_copy_prop_count); + fprintf (dump_file, "%d global const props, %d global copy props\n\n", + global_const_prop_count, global_copy_prop_count); + } + + return changed; +} + + +/* All the passes implemented in this file. Each pass has its + own gate and execute function, and at the end of the file a + pass definition for passes.c. + + We do not construct an accurate cfg in functions which call + setjmp, so none of these passes runs if the function calls + setjmp. + FIXME: Should just handle setjmp via REG_SETJMP notes. */ + static bool -gate_handle_jump_bypass (void) +gate_rtl_cprop (void) { return optimize > 0 && flag_gcse - && dbg_cnt (jump_bypass); + && !cfun->calls_setjmp + && dbg_cnt (cprop); } -/* Perform jump bypassing and control flow optimizations. */ static unsigned int -rest_of_handle_jump_bypass (void) +execute_rtl_cprop (void) { delete_unreachable_blocks (); - if (bypass_jumps ()) - { - delete_trivially_dead_insns (get_insns (), max_reg_num ()); - rebuild_jump_labels (get_insns ()); - cleanup_cfg (0); - } + df_note_add_problem (); + df_set_flags (DF_LR_RUN_DCE); + df_analyze (); + flag_rerun_cse_after_global_opts |= one_cprop_pass (); + return 0; +} + +static bool +gate_rtl_pre (void) +{ + return optimize > 0 && flag_gcse + && !cfun->calls_setjmp + && optimize_function_for_speed_p (cfun) + && dbg_cnt (pre); +} + +static unsigned int +execute_rtl_pre (void) +{ + delete_unreachable_blocks (); + df_note_add_problem (); + df_analyze (); + flag_rerun_cse_after_global_opts |= one_pre_gcse_pass (); + return 0; +} + +static bool +gate_rtl_hoist (void) +{ + return optimize > 0 && flag_gcse + && !cfun->calls_setjmp + /* It does not make sense to run code hoisting unless we are optimizing + for code size -- it rarely makes programs faster, and can make then + bigger if we did PRE (when optimizing for space, we don't run PRE). */ + && optimize_function_for_size_p (cfun) + && dbg_cnt (hoist); +} + +static unsigned int +execute_rtl_hoist (void) +{ + delete_unreachable_blocks (); + df_note_add_problem (); + df_analyze (); + flag_rerun_cse_after_global_opts |= one_code_hoisting_pass (); + return 0; +} + +static bool +gate_rtl_store_motion (void) +{ + return optimize > 0 && flag_gcse_sm + && !cfun->calls_setjmp + && optimize_function_for_speed_p (cfun) + && dbg_cnt (store_motion); +} + +static unsigned int +execute_rtl_store_motion (void) +{ + delete_unreachable_blocks (); + df_note_add_problem (); + df_analyze (); + flag_rerun_cse_after_global_opts |= one_store_motion_pass (); return 0; } -struct rtl_opt_pass pass_jump_bypass = +struct rtl_opt_pass pass_rtl_cprop = { { RTL_PASS, - "bypass", /* name */ - gate_handle_jump_bypass, /* gate */ - rest_of_handle_jump_bypass, /* execute */ + "cprop", /* name */ + gate_rtl_cprop, /* gate */ + execute_rtl_cprop, /* execute */ NULL, /* sub */ NULL, /* next */ 0, /* static_pass_number */ - TV_BYPASS, /* tv_id */ + TV_CPROP, /* tv_id */ PROP_cfglayout, /* properties_required */ 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ + TODO_df_finish | TODO_verify_rtl_sharing | TODO_dump_func | - TODO_ggc_collect | TODO_verify_flow /* todo_flags_finish */ + TODO_verify_flow | TODO_ggc_collect /* todo_flags_finish */ } }; - -static bool -gate_handle_gcse (void) +struct rtl_opt_pass pass_rtl_pre = { - return optimize > 0 && flag_gcse - && dbg_cnt (gcse); -} - - -static unsigned int -rest_of_handle_gcse (void) -{ - int save_csb, save_cfj; - int tem2 = 0, tem; - tem = gcse_main (get_insns ()); - delete_trivially_dead_insns (get_insns (), max_reg_num ()); - rebuild_jump_labels (get_insns ()); - save_csb = flag_cse_skip_blocks; - save_cfj = flag_cse_follow_jumps; - flag_cse_skip_blocks = flag_cse_follow_jumps = 0; - - /* If -fexpensive-optimizations, re-run CSE to clean up things done - by gcse. */ - if (flag_expensive_optimizations) - { - timevar_push (TV_CSE); - tem2 = cse_main (get_insns (), max_reg_num ()); - df_finish_pass (false); - purge_all_dead_edges (); - delete_trivially_dead_insns (get_insns (), max_reg_num ()); - timevar_pop (TV_CSE); - cse_not_expected = !flag_rerun_cse_after_loop; - } - - /* If gcse or cse altered any jumps, rerun jump optimizations to clean - things up. */ - if (tem || tem2 == 2) - { - timevar_push (TV_JUMP); - rebuild_jump_labels (get_insns ()); - cleanup_cfg (0); - timevar_pop (TV_JUMP); - } - else if (tem2 == 1) - cleanup_cfg (0); - - flag_cse_skip_blocks = save_csb; - flag_cse_follow_jumps = save_cfj; - return 0; -} + { + RTL_PASS, + "pre", /* name */ + gate_rtl_pre, /* gate */ + execute_rtl_pre, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_PRE, /* tv_id */ + PROP_cfglayout, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_df_finish | TODO_verify_rtl_sharing | + TODO_dump_func | + TODO_verify_flow | TODO_ggc_collect /* todo_flags_finish */ + } +}; -struct rtl_opt_pass pass_gcse = +struct rtl_opt_pass pass_rtl_hoist = { { RTL_PASS, - "gcse1", /* name */ - gate_handle_gcse, /* gate */ - rest_of_handle_gcse, /* execute */ + "hoist", /* name */ + gate_rtl_hoist, /* gate */ + execute_rtl_hoist, /* execute */ NULL, /* sub */ NULL, /* next */ 0, /* static_pass_number */ - TV_GCSE, /* tv_id */ + TV_HOIST, /* tv_id */ PROP_cfglayout, /* properties_required */ 0, /* properties_provided */ 0, /* properties_destroyed */ @@ -6423,5 +6294,25 @@ struct rtl_opt_pass pass_gcse = } }; +struct rtl_opt_pass pass_rtl_store_motion = +{ + { + RTL_PASS, + "store_motion", /* name */ + gate_rtl_store_motion, /* gate */ + execute_rtl_store_motion, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_LSM, /* tv_id */ + PROP_cfglayout, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_df_finish | TODO_verify_rtl_sharing | + TODO_dump_func | + TODO_verify_flow | TODO_ggc_collect /* todo_flags_finish */ + } +}; #include "gt-gcse.h" diff --git a/gcc/passes.c b/gcc/passes.c index 60a24866265..312dfa9db72 100644 --- a/gcc/passes.c +++ b/gcc/passes.c @@ -729,7 +729,12 @@ init_optimization_passes (void) NEXT_PASS (pass_df_initialize_opt); NEXT_PASS (pass_cse); NEXT_PASS (pass_rtl_fwprop); - NEXT_PASS (pass_gcse); + NEXT_PASS (pass_rtl_cprop); + NEXT_PASS (pass_rtl_pre); + NEXT_PASS (pass_rtl_hoist); + NEXT_PASS (pass_rtl_cprop); + NEXT_PASS (pass_rtl_store_motion); + NEXT_PASS (pass_cse_after_global_opts); NEXT_PASS (pass_rtl_ifcvt); /* Perform loop optimizations. It might be better to do them a bit sooner, but we want the profile feedback to work more @@ -746,7 +751,7 @@ init_optimization_passes (void) *p = NULL; } NEXT_PASS (pass_web); - NEXT_PASS (pass_jump_bypass); + NEXT_PASS (pass_rtl_cprop); NEXT_PASS (pass_cse2); NEXT_PASS (pass_rtl_dse1); NEXT_PASS (pass_rtl_fwprop_addr); diff --git a/gcc/timevar.def b/gcc/timevar.def index d65c7389a68..d3510a23af0 100644 --- a/gcc/timevar.def +++ b/gcc/timevar.def @@ -154,13 +154,10 @@ DEFTIMEVAR (TV_DCE , "dead code elimination") DEFTIMEVAR (TV_DSE1 , "dead store elim1") DEFTIMEVAR (TV_DSE2 , "dead store elim2") DEFTIMEVAR (TV_LOOP , "loop analysis") -DEFTIMEVAR (TV_GCSE , "global CSE") -DEFTIMEVAR (TV_CPROP1 , "CPROP 1") +DEFTIMEVAR (TV_CPROP , "CPROP") DEFTIMEVAR (TV_PRE , "PRE") DEFTIMEVAR (TV_HOIST , "code hoisting") -DEFTIMEVAR (TV_CPROP2 , "CPROP 2") DEFTIMEVAR (TV_LSM , "LSM") -DEFTIMEVAR (TV_BYPASS , "bypass jumps") DEFTIMEVAR (TV_TRACER , "tracer") DEFTIMEVAR (TV_WEB , "web") DEFTIMEVAR (TV_AUTO_INC_DEC , "auto inc dec") diff --git a/gcc/toplev.h b/gcc/toplev.h index 15180c36f95..28f5d0c4b17 100644 --- a/gcc/toplev.h +++ b/gcc/toplev.h @@ -132,6 +132,7 @@ extern int flag_if_conversion; extern int flag_if_conversion2; extern int flag_keep_static_consts; extern int flag_peel_loops; +extern int flag_rerun_cse_after_global_opts; extern int flag_rerun_cse_after_loop; extern int flag_thread_jumps; extern int flag_tracer; diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h index 9f80bfd9598..8ce7c3ae81b 100644 --- a/gcc/tree-pass.h +++ b/gcc/tree-pass.h @@ -394,6 +394,7 @@ extern struct gimple_opt_pass pass_rebuild_cgraph_edges; extern struct gimple_opt_pass pass_remove_cgraph_callee_edges; extern struct gimple_opt_pass pass_build_cgraph_edges; extern struct gimple_opt_pass pass_local_pure_const; +extern struct gimple_opt_pass pass_tracer; /* IPA Passes */ extern struct ipa_opt_pass pass_ipa_inline; @@ -433,11 +434,12 @@ extern struct rtl_opt_pass pass_rtl_dce; extern struct rtl_opt_pass pass_rtl_dse1; extern struct rtl_opt_pass pass_rtl_dse2; extern struct rtl_opt_pass pass_rtl_dse3; -extern struct rtl_opt_pass pass_gcse; -extern struct rtl_opt_pass pass_jump_bypass; -extern struct rtl_opt_pass pass_profiling; +extern struct rtl_opt_pass pass_rtl_cprop; +extern struct rtl_opt_pass pass_rtl_pre; +extern struct rtl_opt_pass pass_rtl_hoist; +extern struct rtl_opt_pass pass_rtl_store_motion; +extern struct rtl_opt_pass pass_cse_after_global_opts; extern struct rtl_opt_pass pass_rtl_ifcvt; -extern struct gimple_opt_pass pass_tracer; extern struct rtl_opt_pass pass_into_cfg_layout_mode; extern struct rtl_opt_pass pass_outof_cfg_layout_mode; |