X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fgcse.c;h=00f09862cb6ab12f7cd87d063dd48b8d69ed870a;hb=c80cefd7b6f98689eaf677f6124146225001001a;hp=828ee6b32543860085a85e5d3d099771bdc6324d;hpb=a0877a20338f2e5dbc1d2162119ea0feba2dd261;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/gcse.c b/gcc/gcse.c index 828ee6b3254..00f09862cb6 100644 --- a/gcc/gcse.c +++ b/gcc/gcse.c @@ -1,13 +1,13 @@ /* Global common subexpression elimination/Partial redundancy elimination and global constant/copy propagation for GNU compiler. Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, - 2006, 2007 Free Software Foundation, Inc. + 2006, 2007, 2008 Free Software Foundation, Inc. This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later +Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY @@ -16,9 +16,8 @@ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301, USA. */ +along with GCC; see the file COPYING3. If not see +. */ /* TODO - reordering of memory allocation and freeing to be more space efficient @@ -191,16 +190,18 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA We perform the following steps: - 1) Compute basic block information. + 1) Compute table of places where registers are set. - 2) Compute table of places where registers are set. + 2) Perform copy/constant propagation. - 3) Perform copy/constant propagation. - - 4) Perform global cse using lazy code motion if not optimizing + 3) Perform global cse using lazy code motion if not optimizing for size, or code hoisting if we are. - 5) Perform another pass of copy/constant propagation. + 4) Perform another pass of copy/constant propagation. Try to bypass + conditional jumps if the condition can be computed from a value of + an incoming edge. + + 5) Perform store motion. Two passes of copy/constant propagation are done because the first one enables more GCSE and the second one helps to clean up the copies that @@ -213,6 +214,11 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA (set (pseudo-reg) (expression)). Function want_to_gcse_p says what these are. + In addition, expressions in REG_EQUAL notes are candidates for GXSE-ing. + This allows PRE to hoist expressions that are expressed in multiple insns, + such as comprex address calculations (e.g. for PIC code, or loads with a + high part and as lowe part). + PRE handles moving invariant expressions out of loops (by treating them as partially redundant). @@ -236,9 +242,13 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA It was found doing copy propagation between each pass enables further substitutions. + This study was done before expressions in REG_EQUAL notes were added as + candidate expressions for optimization, and before the GIMPLE optimizers + were added. Probably, multiple passes is even less efficient now than + at the time when the study was conducted. + PRE is quite expensive in complicated functions because the DFA can take - a while to converge. Hence we only perform one pass. The parameter - max-gcse-passes can be modified if one wants to experiment. + a while to converge. Hence we only perform one pass. ********************** @@ -381,12 +391,6 @@ static int max_uid; /* Number of cuids. */ static int max_cuid; -/* Mapping of cuids to insns. */ -static rtx *cuid_insn; - -/* Get insn from cuid. */ -#define CUID_INSN(CUID) (cuid_insn[CUID]) - /* 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. */ @@ -524,27 +528,27 @@ static void free_gcse_mem (void); static void alloc_reg_set_mem (int); static void free_reg_set_mem (void); static void record_one_set (int, rtx); -static void record_set_info (rtx, rtx, void *); +static void record_set_info (rtx, const_rtx, void *); static void compute_sets (void); -static void hash_scan_insn (rtx, struct hash_table *, int); +static void hash_scan_insn (rtx, struct hash_table *); static void hash_scan_set (rtx, rtx, struct hash_table *); static void hash_scan_clobber (rtx, rtx, struct hash_table *); static void hash_scan_call (rtx, rtx, struct hash_table *); static int want_to_gcse_p (rtx); static bool can_assign_to_reg_p (rtx); -static bool gcse_constant_p (rtx); -static int oprs_unchanged_p (rtx, rtx, int); -static int oprs_anticipatable_p (rtx, rtx); -static int oprs_available_p (rtx, rtx); +static bool gcse_constant_p (const_rtx); +static int oprs_unchanged_p (const_rtx, const_rtx, int); +static int oprs_anticipatable_p (const_rtx, const_rtx); +static int oprs_available_p (const_rtx, const_rtx); static void insert_expr_in_table (rtx, enum machine_mode, rtx, int, int, struct hash_table *); static void insert_set_in_table (rtx, rtx, struct hash_table *); -static unsigned int hash_expr (rtx, enum machine_mode, int *, int); +static unsigned int hash_expr (const_rtx, enum machine_mode, int *, int); static unsigned int hash_set (int, int); -static int expr_equiv_p (rtx, rtx); +static int expr_equiv_p (const_rtx, const_rtx); static void record_last_reg_set_info (rtx, int); static void record_last_mem_set_info (rtx); -static void record_last_set_info (rtx, rtx, void *); +static void record_last_set_info (rtx, const_rtx, void *); static void compute_hash_table (struct hash_table *); static void alloc_hash_table (int, struct hash_table *, int); static void free_hash_table (struct hash_table *); @@ -553,14 +557,14 @@ static void dump_hash_table (FILE *, const char *, struct hash_table *); static struct expr *lookup_set (unsigned int, struct hash_table *); static struct expr *next_set (unsigned int, struct expr *); static void reset_opr_set_tables (void); -static int oprs_not_set_p (rtx, rtx); +static int oprs_not_set_p (const_rtx, const_rtx); static void mark_call (rtx); static void mark_set (rtx, rtx); static void mark_clobber (rtx, rtx); static void mark_oprs_set (rtx); static void alloc_cprop_mem (int, int); static void free_cprop_mem (void); -static void compute_transp (rtx, int, sbitmap *, int); +static void compute_transp (const_rtx, int, sbitmap *, int); static void compute_transpout (void); static void compute_local_properties (sbitmap *, sbitmap *, sbitmap *, struct hash_table *); @@ -569,16 +573,16 @@ static void find_used_regs (rtx *, void *); static int try_replace_reg (rtx, rtx, rtx); static struct expr *find_avail_set (int, rtx); static int cprop_jump (basic_block, rtx, rtx, rtx, rtx); -static void mems_conflict_for_gcse_p (rtx, rtx, void *); -static int load_killed_in_block_p (basic_block, int, rtx, int); -static void canon_list_insert (rtx, rtx, void *); +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 void find_implicit_sets (void); static int one_cprop_pass (int, bool, bool); static bool constprop_register (rtx, rtx, rtx, bool); static struct expr *find_bypass_set (int, int); -static bool reg_killed_on_edge (rtx, edge); +static bool reg_killed_on_edge (const_rtx, const_edge); static int bypass_block (basic_block, rtx, rtx); static int bypass_conditional_jumps (void); static void alloc_pre_mem (int, int); @@ -612,23 +616,23 @@ static struct ls_expr * find_rtx_in_ldst (rtx); static int enumerate_ldsts (void); static inline struct ls_expr * first_ls_expr (void); static inline struct ls_expr * next_ls_expr (struct ls_expr *); -static int simple_mem (rtx); +static int simple_mem (const_rtx); static void invalidate_any_buried_refs (rtx); static void compute_ld_motion_mems (void); static void trim_ld_motion_mems (void); static void update_ld_motion_stores (struct expr *); -static void reg_set_info (rtx, rtx, void *); -static void reg_clear_last_set (rtx, rtx, void *); -static bool store_ops_ok (rtx, int *); +static void reg_set_info (rtx, const_rtx, void *); +static void reg_clear_last_set (rtx, const_rtx, void *); +static bool store_ops_ok (const_rtx, int *); static rtx extract_mentioned_regs (rtx); static rtx extract_mentioned_regs_helper (rtx, rtx); static void find_moveable_store (rtx, int *, int *); static int compute_store_table (void); -static bool load_kills_store (rtx, rtx, int); -static bool find_loads (rtx, rtx, int); -static bool store_killed_in_insn (rtx, rtx, rtx, int); -static bool store_killed_after (rtx, rtx, rtx, basic_block, int *, rtx *); -static bool store_killed_before (rtx, rtx, rtx, basic_block, int *); +static bool load_kills_store (const_rtx, const_rtx, int); +static bool find_loads (const_rtx, const_rtx, int); +static bool store_killed_in_insn (const_rtx, const_rtx, const_rtx, int); +static bool store_killed_after (const_rtx, const_rtx, const_rtx, const_basic_block, int *, rtx *); +static bool store_killed_before (const_rtx, const_rtx, const_rtx, const_basic_block, int *); static void build_store_vectors (void); static void insert_insn_start_basic_block (rtx, basic_block); static int insert_store (struct ls_expr *, edge); @@ -642,10 +646,23 @@ 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, rtx*); -static bool adjust_libcall_notes (rtx, rtx, rtx, rtx*); +static bool do_local_cprop (rtx, rtx, bool); static void local_cprop_pass (bool); static bool is_too_expensive (const char *); + +#define GNEW(T) ((T *) gmalloc (sizeof (T))) +#define GCNEW(T) ((T *) gcalloc (1, sizeof (T))) + +#define GNEWVEC(T, N) ((T *) gmalloc (sizeof (T) * (N))) +#define GCNEWVEC(T, N) ((T *) gcalloc ((N), sizeof (T))) +#define GRESIZEVEC(T, P, N) ((T *) grealloc ((void *) (P), sizeof (T) * (N))) + +#define GNEWVAR(T, S) ((T *) gmalloc ((S))) +#define GCNEWVAR(T, S) ((T *) gcalloc (1, (S))) +#define GRESIZEVAR(T, P, S) ((T *) grealloc ((P), (S))) + +#define GOBNEW(T) ((T *) gcse_alloc (sizeof (T))) +#define GOBNEWVAR(T, S) ((T *) gcse_alloc ((S))) /* Entry point for global common subexpression elimination. @@ -655,17 +672,13 @@ static bool is_too_expensive (const char *); static int gcse_main (rtx f ATTRIBUTE_UNUSED) { - int changed, pass; - /* Bytes used at start of pass. */ - int initial_bytes_used; - /* Maximum number of bytes used by a pass. */ - int max_pass_bytes; + 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 (current_function_calls_setjmp) + if (cfun->calls_setjmp) return 0; /* Assume that we do not need to run jump optimizations after gcse. */ @@ -691,6 +704,7 @@ gcse_main (rtx f ATTRIBUTE_UNUSED) /* We need alias. */ init_alias_analysis (); + /* Record where pseudo-registers are set. This data is kept accurate during each pass. ??? We could also record hard-reg information here [since it's unchanging], however it is currently done during hash table @@ -698,121 +712,114 @@ gcse_main (rtx f ATTRIBUTE_UNUSED) It may be tempting to compute MEM set information here too, but MEM sets will be subject to code motion one day and thus we need to compute - information about memory sets when we build the hash tables. */ + information about memory sets when we build the hash tables. + + ??? Actually, we already know the information that compute_sets computes + because it is available from DF. FIXME. */ alloc_reg_set_mem (max_gcse_regno); compute_sets (); - pass = 0; - initial_bytes_used = bytes_used; - max_pass_bytes = 0; - gcse_obstack_bottom = gcse_alloc (1); - changed = 1; - while (changed && pass < MAX_GCSE_PASSES) - { - changed = 0; - if (dump_file) - fprintf (dump_file, "GCSE pass %d\n\n", pass + 1); - - /* Initialize bytes_used to the space for the pred/succ lists, - and the reg_set_table data. */ - bytes_used = initial_bytes_used; + gcse_obstack_bottom = GOBNEWVAR (char, 1); + changed = 0; + + if (dump_file) + fprintf (dump_file, "GCSE pass\n\n"); - /* Each pass may create new registers, so recalculate each time. */ - max_gcse_regno = max_reg_num (); + max_gcse_regno = max_reg_num (); - alloc_gcse_mem (); + alloc_gcse_mem (); - /* Don't allow constant propagation to modify jumps - during this pass. */ + /* Don't allow constant propagation to modify jumps + during this pass. */ + if (dbg_cnt (cprop1)) + { timevar_push (TV_CPROP1); - changed = one_cprop_pass (pass + 1, false, false); + changed = one_cprop_pass (1, false, false); timevar_pop (TV_CPROP1); + } - if (optimize_size) - /* Do nothing. */ ; - else + 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) { - timevar_push (TV_PRE); - changed |= one_pre_gcse_pass (pass + 1); - /* We may have just created new basic blocks. Release and - recompute various things which are sized on the number of - basic blocks. */ - if (changed) - { - free_modify_mem_tables (); - modify_mem_list = gcalloc (last_basic_block, sizeof (rtx)); - canon_modify_mem_list = gcalloc (last_basic_block, sizeof (rtx)); - } - free_reg_set_mem (); - alloc_reg_set_mem (max_reg_num ()); - compute_sets (); - run_jump_opt_after_gcse = 1; - timevar_pop (TV_PRE); + free_modify_mem_tables (); + modify_mem_list = GCNEWVEC (rtx, last_basic_block); + canon_modify_mem_list = GCNEWVEC (rtx, last_basic_block); } - if (max_pass_bytes < bytes_used) - max_pass_bytes = bytes_used; - - /* Free up memory, then reallocate for code hoisting. We can - not re-use the existing allocated memory because the tables - will not have info for the insns or registers created by - partial redundancy elimination. */ - free_gcse_mem (); - - /* It does not make sense to run code hoisting unless we are optimizing + /* ??? When we allocate this at the start of the function, + the comment says that "this data is kept accurate during + each pass". Apparently this is not so? FIXME. */ + free_reg_set_mem (); + alloc_reg_set_mem (max_reg_num ()); + compute_sets (); + 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). */ - if (optimize_size) - { - timevar_push (TV_HOIST); - max_gcse_regno = max_reg_num (); - alloc_gcse_mem (); - changed |= one_code_hoisting_pass (); - free_gcse_mem (); - - if (max_pass_bytes < bytes_used) - max_pass_bytes = bytes_used; - timevar_pop (TV_HOIST); - } + timevar_push (TV_HOIST); + max_gcse_regno = max_reg_num (); + alloc_gcse_mem (); + one_code_hoisting_pass (); + timevar_pop (TV_HOIST); + } - if (dump_file) - { - fprintf (dump_file, "\n"); - fflush (dump_file); - } + free_gcse_mem (); - obstack_free (&gcse_obstack, gcse_obstack_bottom); - pass++; + if (dump_file) + { + fprintf (dump_file, "\n"); + fflush (dump_file); } - /* Do one last pass of copy propagation, including cprop into + 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 (); - max_gcse_regno = max_reg_num (); - alloc_gcse_mem (); - /* This time, go ahead and allow cprop to alter jumps. */ - timevar_push (TV_CPROP2); - one_cprop_pass (pass + 1, true, true); - timevar_pop (TV_CPROP2); - free_gcse_mem (); + /* This time, go ahead and allow cprop to alter jumps. */ + timevar_push (TV_CPROP2); + one_cprop_pass (2, true, true); + 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, "%d pass%s, %d bytes\n\n", - pass, pass > 1 ? "es" : "", max_pass_bytes); + fprintf (dump_file, "pass 1, %d bytes\n\n", bytes_used); } obstack_free (&gcse_obstack, NULL); free_reg_set_mem (); - /* We are finished with alias. */ + /* We are finished with alias. + ??? Actually we recompute alias in store_motion. */ end_alias_analysis (); - if (!optimize_size && flag_gcse_sm) + /* Run store motion. */ + if (optimize_function_for_speed_p (cfun) && flag_gcse_sm) { timevar_push (TV_LSM); store_motion (); @@ -932,7 +939,7 @@ alloc_gcse_mem (void) but we should never see those anyway, so this is OK.) */ max_uid = get_max_uid (); - uid_cuid = gcalloc (max_uid + 1, sizeof (int)); + uid_cuid = GCNEWVEC (int, max_uid + 1); i = 0; FOR_EACH_BB (bb) FOR_BB_INSNS (bb, insn) @@ -943,15 +950,7 @@ alloc_gcse_mem (void) uid_cuid[INSN_UID (insn)] = i; } - /* Create a table mapping cuids to insns. */ - max_cuid = i; - cuid_insn = gcalloc (max_cuid + 1, sizeof (rtx)); - i = 0; - FOR_EACH_BB (bb) - FOR_BB_INSNS (bb, insn) - if (INSN_P (insn)) - CUID_INSN (i++) = insn; /* Allocate vars to track sets of regs. */ reg_set_bitmap = BITMAP_ALLOC (NULL); @@ -960,8 +959,8 @@ alloc_gcse_mem (void) reg_set_in_block = sbitmap_vector_alloc (last_basic_block, max_gcse_regno); /* Allocate array to keep a list of insns which modify memory in each basic block. */ - modify_mem_list = gcalloc (last_basic_block, sizeof (rtx)); - canon_modify_mem_list = gcalloc (last_basic_block, sizeof (rtx)); + modify_mem_list = GCNEWVEC (rtx, last_basic_block); + canon_modify_mem_list = GCNEWVEC (rtx, last_basic_block); modify_mem_list_set = BITMAP_ALLOC (NULL); blocks_with_calls = BITMAP_ALLOC (NULL); } @@ -972,7 +971,6 @@ static void free_gcse_mem (void) { free (uid_cuid); - free (cuid_insn); BITMAP_FREE (reg_set_bitmap); @@ -1086,7 +1084,7 @@ static void alloc_reg_set_mem (int n_regs) { reg_set_table_size = n_regs + REG_SET_TABLE_SLOP; - reg_set_table = gcalloc (reg_set_table_size, sizeof (struct reg_set *)); + reg_set_table = GCNEWVEC (struct reg_set *, reg_set_table_size); gcc_obstack_init (®_set_obstack); } @@ -1111,14 +1109,13 @@ record_one_set (int regno, rtx insn) { int new_size = regno + REG_SET_TABLE_SLOP; - reg_set_table = grealloc (reg_set_table, - new_size * sizeof (struct reg_set *)); + reg_set_table = GRESIZEVEC (struct reg_set *, reg_set_table, new_size); memset (reg_set_table + reg_set_table_size, 0, (new_size - reg_set_table_size) * sizeof (struct reg_set *)); reg_set_table_size = new_size; } - new_reg_info = obstack_alloc (®_set_obstack, sizeof (struct reg_set)); + new_reg_info = XOBNEW (®_set_obstack, struct reg_set); bytes_used += sizeof (struct reg_set); new_reg_info->bb_index = BLOCK_NUM (insn); new_reg_info->next = reg_set_table[regno]; @@ -1130,7 +1127,7 @@ record_one_set (int regno, rtx insn) occurring. */ static void -record_set_info (rtx dest, rtx setter ATTRIBUTE_UNUSED, void *data) +record_set_info (rtx dest, const_rtx setter ATTRIBUTE_UNUSED, void *data) { rtx record_set_insn = (rtx) data; @@ -1188,6 +1185,7 @@ want_to_gcse_p (rtx x) case SUBREG: case CONST_INT: case CONST_DOUBLE: + case CONST_FIXED: case CONST_VECTOR: case CALL: return 0; @@ -1240,7 +1238,7 @@ can_assign_to_reg_p (rtx x) or from INSN to the end of INSN's basic block (if AVAIL_P != 0). */ static int -oprs_unchanged_p (rtx x, rtx insn, int avail_p) +oprs_unchanged_p (const_rtx x, const_rtx insn, int avail_p) { int i, j; enum rtx_code code; @@ -1284,6 +1282,7 @@ oprs_unchanged_p (rtx x, rtx insn, int avail_p) case CONST: case CONST_INT: case CONST_DOUBLE: + case CONST_FIXED: case CONST_VECTOR: case SYMBOL_REF: case LABEL_REF: @@ -1326,14 +1325,14 @@ static int gcse_mems_conflict_p; load_killed_in_block_p. A memory reference for a load instruction, mems_conflict_for_gcse_p will see if a memory store conflicts with this memory load. */ -static rtx gcse_mem_operand; +static const_rtx gcse_mem_operand; /* DEST is the output of an instruction. If it is a memory reference, and possibly conflicts with the load found in gcse_mem_operand, then set gcse_mems_conflict_p to a nonzero value. */ static void -mems_conflict_for_gcse_p (rtx dest, rtx setter ATTRIBUTE_UNUSED, +mems_conflict_for_gcse_p (rtx dest, const_rtx setter ATTRIBUTE_UNUSED, void *data ATTRIBUTE_UNUSED) { while (GET_CODE (dest) == SUBREG @@ -1371,7 +1370,7 @@ mems_conflict_for_gcse_p (rtx dest, rtx setter ATTRIBUTE_UNUSED, AVAIL_P to 0. */ static int -load_killed_in_block_p (basic_block bb, int uid_limit, rtx x, int avail_p) +load_killed_in_block_p (const_basic_block bb, int uid_limit, const_rtx x, int avail_p) { rtx list_entry = modify_mem_list[bb->index]; @@ -1419,7 +1418,7 @@ load_killed_in_block_p (basic_block bb, int uid_limit, rtx x, int avail_p) the start of INSN's basic block up to but not including INSN. */ static int -oprs_anticipatable_p (rtx x, rtx insn) +oprs_anticipatable_p (const_rtx x, const_rtx insn) { return oprs_unchanged_p (x, insn, 0); } @@ -1428,7 +1427,7 @@ oprs_anticipatable_p (rtx x, rtx insn) INSN to the end of INSN's basic block. */ static int -oprs_available_p (rtx x, rtx insn) +oprs_available_p (const_rtx x, const_rtx insn) { return oprs_unchanged_p (x, insn, 1); } @@ -1441,7 +1440,7 @@ oprs_available_p (rtx x, rtx insn) the current size of the hash table to be probed. */ static unsigned int -hash_expr (rtx x, enum machine_mode mode, int *do_not_record_p, +hash_expr (const_rtx x, enum machine_mode mode, int *do_not_record_p, int hash_table_size) { unsigned int hash; @@ -1472,7 +1471,7 @@ hash_set (int regno, int hash_table_size) /* Return nonzero if exp1 is equivalent to exp2. */ static int -expr_equiv_p (rtx x, rtx y) +expr_equiv_p (const_rtx x, const_rtx y) { return exp_equiv_p (x, y, 0, true); } @@ -1517,7 +1516,7 @@ insert_expr_in_table (rtx x, enum machine_mode mode, rtx insn, int antic_p, if (! found) { - cur_expr = gcse_alloc (sizeof (struct expr)); + cur_expr = GOBNEW (struct expr); bytes_used += sizeof (struct expr); if (table->table[hash] == NULL) /* This is the first pattern that hashed to this index. */ @@ -1550,7 +1549,7 @@ insert_expr_in_table (rtx x, enum machine_mode mode, rtx insn, int antic_p, else { /* First occurrence of this expression in this basic block. */ - antic_occr = gcse_alloc (sizeof (struct occr)); + antic_occr = GOBNEW (struct occr); bytes_used += sizeof (struct occr); antic_occr->insn = insn; antic_occr->next = cur_expr->antic_occr; @@ -1574,7 +1573,7 @@ insert_expr_in_table (rtx x, enum machine_mode mode, rtx insn, int antic_p, else { /* First occurrence of this expression in this basic block. */ - avail_occr = gcse_alloc (sizeof (struct occr)); + avail_occr = GOBNEW (struct occr); bytes_used += sizeof (struct occr); avail_occr->insn = insn; avail_occr->next = cur_expr->avail_occr; @@ -1614,7 +1613,7 @@ insert_set_in_table (rtx x, rtx insn, struct hash_table *table) if (! found) { - cur_expr = gcse_alloc (sizeof (struct expr)); + cur_expr = GOBNEW (struct expr); bytes_used += sizeof (struct expr); if (table->table[hash] == NULL) /* This is the first pattern that hashed to this index. */ @@ -1647,7 +1646,7 @@ insert_set_in_table (rtx x, rtx insn, struct hash_table *table) else { /* First occurrence of this expression in this basic block. */ - cur_occr = gcse_alloc (sizeof (struct occr)); + cur_occr = GOBNEW (struct occr); bytes_used += sizeof (struct occr); cur_occr->insn = insn; @@ -1661,7 +1660,7 @@ insert_set_in_table (rtx x, rtx insn, struct hash_table *table) the purposes of GCSE's constant propagation. */ static bool -gcse_constant_p (rtx x) +gcse_constant_p (const_rtx x) { /* Consider a COMPARE of two integers constant. */ if (GET_CODE (x) == COMPARE @@ -1699,12 +1698,25 @@ hash_scan_set (rtx pat, rtx insn, struct hash_table *table) unsigned int regno = REGNO (dest); rtx tmp; - /* See if a REG_NOTE shows this equivalent to a simpler expression. + /* See if a REG_EQUAL note shows this equivalent to a simpler expression. + This allows us to do a single GCSE pass and still eliminate redundant constants, addresses or other expressions that are - constructed with multiple instructions. */ + constructed with multiple instructions. + + However, keep the original SRC if INSN is a simple reg-reg move. In + In this case, there will almost always be a REG_EQUAL note on the + insn that sets SRC. By recording the REG_EQUAL value here as SRC + for INSN, we miss copy propagation opportunities and we perform the + same PRE GCSE operation repeatedly on the same REG_EQUAL value if we + do more than one PRE GCSE pass. + + Note that this does not impede profitable constant propagations. We + "look through" reg-reg sets in lookup_avail_set. */ note = find_reg_equal_equiv_note (insn); if (note != 0 + && REG_NOTE_KIND (note) == REG_EQUAL + && !REG_P (src) && (table->set_p ? gcse_constant_p (XEXP (note, 0)) : want_to_gcse_p (XEXP (note, 0)))) @@ -1759,8 +1771,9 @@ hash_scan_set (rtx pat, rtx insn, struct hash_table *table) modified. Here we want to search from INSN+1 on, but oprs_available_p searches from INSN on. */ && (insn == BB_END (BLOCK_FOR_INSN (insn)) - || ((tmp = next_nonnote_insn (insn)) != NULL_RTX - && oprs_available_p (pat, tmp)))) + || (tmp = next_nonnote_insn (insn)) == NULL_RTX + || BLOCK_FOR_INSN (tmp) != BLOCK_FOR_INSN (insn) + || oprs_available_p (pat, tmp))) insert_set_in_table (pat, insn, table); } /* In case of store we want to consider the memory value as available in @@ -1831,19 +1844,14 @@ hash_scan_call (rtx x ATTRIBUTE_UNUSED, rtx insn ATTRIBUTE_UNUSED, are also in the PARALLEL. Later. If SET_P is nonzero, this is for the assignment hash table, - otherwise it is for the expression hash table. - If IN_LIBCALL_BLOCK nonzero, we are in a libcall block, and should - not record any expressions. */ + otherwise it is for the expression hash table. */ static void -hash_scan_insn (rtx insn, struct hash_table *table, int in_libcall_block) +hash_scan_insn (rtx insn, struct hash_table *table) { rtx pat = PATTERN (insn); int i; - if (in_libcall_block) - return; - /* Pick out the sets of INSN and for other forms of instructions record what's been modified. */ @@ -1877,8 +1885,8 @@ dump_hash_table (FILE *file, const char *name, struct hash_table *table) unsigned int *hash_val; struct expr *expr; - flat_table = xcalloc (table->n_elems, sizeof (struct expr *)); - hash_val = xmalloc (table->n_elems * sizeof (unsigned int)); + flat_table = XCNEWVEC (struct expr *, table->n_elems); + hash_val = XNEWVEC (unsigned int, table->n_elems); for (i = 0; i < (int) table->size; i++) for (expr = table->table[i]; expr != NULL; expr = expr->next_same_hash) @@ -1941,7 +1949,7 @@ record_last_reg_set_info (rtx insn, int regno) taken off pairwise. */ static void -canon_list_insert (rtx dest ATTRIBUTE_UNUSED, rtx unused1 ATTRIBUTE_UNUSED, +canon_list_insert (rtx dest ATTRIBUTE_UNUSED, const_rtx unused1 ATTRIBUTE_UNUSED, void * v_insn) { rtx dest_addr, insn; @@ -2002,7 +2010,7 @@ record_last_mem_set_info (rtx insn) the SET is taking place. */ static void -record_last_set_info (rtx dest, rtx setter ATTRIBUTE_UNUSED, void *data) +record_last_set_info (rtx dest, const_rtx setter ATTRIBUTE_UNUSED, void *data) { rtx last_set_insn = (rtx) data; @@ -2047,7 +2055,7 @@ compute_hash_table_work (struct hash_table *table) /* 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 = gmalloc (max_gcse_regno * sizeof (struct reg_avail_info)); + reg_avail_info = GNEWVEC (struct reg_avail_info, max_gcse_regno); for (i = 0; i < max_gcse_regno; ++i) reg_avail_info[i].last_bb = NULL; @@ -2056,7 +2064,6 @@ compute_hash_table_work (struct hash_table *table) { rtx insn; unsigned int regno; - int in_libcall_block; /* First pass over the instructions records information used to determine when registers and memory are first and last set. @@ -2087,18 +2094,9 @@ compute_hash_table_work (struct hash_table *table) BB_HEAD (current_bb), table); /* The next pass builds the hash table. */ - in_libcall_block = 0; FOR_BB_INSNS (current_bb, insn) if (INSN_P (insn)) - { - if (find_reg_note (insn, REG_LIBCALL, NULL_RTX)) - in_libcall_block = 1; - else if (table->set_p && find_reg_note (insn, REG_RETVAL, NULL_RTX)) - in_libcall_block = 0; - hash_scan_insn (insn, table, in_libcall_block); - if (!table->set_p && find_reg_note (insn, REG_RETVAL, NULL_RTX)) - in_libcall_block = 0; - } + hash_scan_insn (insn, table); } free (reg_avail_info); @@ -2125,7 +2123,7 @@ alloc_hash_table (int n_insns, struct hash_table *table, int set_p) ??? Later take some measurements. */ table->size |= 1; n = table->size * sizeof (struct expr *); - table->table = gmalloc (n); + table->table = GNEWVAR (struct expr *, n); table->set_p = set_p; } @@ -2249,7 +2247,7 @@ reset_opr_set_tables (void) INSN's basic block. */ static int -oprs_not_set_p (rtx x, rtx insn) +oprs_not_set_p (const_rtx x, const_rtx insn) { int i, j; enum rtx_code code; @@ -2266,6 +2264,7 @@ oprs_not_set_p (rtx x, rtx insn) case CONST: case CONST_INT: case CONST_DOUBLE: + case CONST_FIXED: case CONST_VECTOR: case SYMBOL_REF: case LABEL_REF: @@ -2314,7 +2313,7 @@ oprs_not_set_p (rtx x, rtx insn) static void mark_call (rtx insn) { - if (! CONST_OR_PURE_CALL_P (insn)) + if (! RTL_CONST_OR_PURE_CALL_P (insn)) record_last_mem_set_info (insn); } @@ -2427,7 +2426,7 @@ free_cprop_mem (void) bit in BMAP. */ static void -compute_transp (rtx x, int indx, sbitmap *bmap, int set_p) +compute_transp (const_rtx x, int indx, sbitmap *bmap, int set_p) { int i, j; basic_block bb; @@ -2534,6 +2533,7 @@ compute_transp (rtx x, int indx, sbitmap *bmap, int set_p) case CONST: case CONST_INT: case CONST_DOUBLE: + case CONST_FIXED: case CONST_VECTOR: case SYMBOL_REF: case LABEL_REF: @@ -2676,7 +2676,8 @@ try_replace_reg (rtx from, rtx to, rtx insn) with our replacement. */ if (note != 0 && REG_NOTE_KIND (note) == REG_EQUAL) set_unique_reg_note (insn, REG_EQUAL, - simplify_replace_rtx (XEXP (note, 0), from, to)); + simplify_replace_rtx (XEXP (note, 0), from, + copy_rtx (to))); if (!success && set && reg_mentioned_p (from, SET_SRC (set))) { /* If above failed and this is a single set, try to simplify the source of @@ -2784,7 +2785,7 @@ find_avail_set (int regno, rtx insn) static int cprop_jump (basic_block bb, rtx setcc, rtx jump, rtx from, rtx src) { - rtx new, set_src, note_src; + rtx new_rtx, set_src, note_src; rtx set = pc_set (jump); rtx note = find_reg_equal_equiv_note (jump); @@ -2816,22 +2817,22 @@ cprop_jump (basic_block bb, rtx setcc, rtx jump, rtx from, rtx src) else setcc = NULL_RTX; - new = simplify_replace_rtx (set_src, from, src); + new_rtx = simplify_replace_rtx (set_src, from, src); /* If no simplification can be made, then try the next register. */ - if (rtx_equal_p (new, SET_SRC (set))) + if (rtx_equal_p (new_rtx, SET_SRC (set))) return 0; /* If this is now a no-op delete it, otherwise this must be a valid insn. */ - if (new == pc_rtx) + if (new_rtx == pc_rtx) delete_insn (jump); else { /* Ensure the value computed inside the jump insn to be equivalent to one computed by setcc. */ - if (setcc && modified_in_p (new, setcc)) + if (setcc && modified_in_p (new_rtx, setcc)) return 0; - if (! validate_change (jump, &SET_SRC (set), new, 0)) + if (! validate_unshare_change (jump, &SET_SRC (set), new_rtx, 0)) { /* When (some) constants are not valid in a comparison, and there are two registers to be replaced by constants before the entire @@ -2842,8 +2843,8 @@ cprop_jump (basic_block bb, rtx setcc, rtx jump, rtx from, rtx src) we need to attach a note to the branch itself to make this optimization work. */ - if (!rtx_equal_p (new, note_src)) - set_unique_reg_note (jump, REG_EQUAL, copy_rtx (new)); + if (!rtx_equal_p (new_rtx, note_src)) + set_unique_reg_note (jump, REG_EQUAL, copy_rtx (new_rtx)); return 0; } @@ -2871,6 +2872,24 @@ cprop_jump (basic_block bb, rtx setcc, rtx jump, rtx from, rtx src) } purge_dead_edges (bb); + /* If a conditional jump has been changed into unconditional jump, remove + the jump and make the edge fallthru - this is always called in + cfglayout mode. */ + if (new_rtx != pc_rtx && simplejump_p (jump)) + { + edge e; + edge_iterator ei; + + for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); ei_next (&ei)) + if (e->dest != EXIT_BLOCK_PTR + && BB_HEAD (e->dest) == JUMP_LABEL (jump)) + { + e->flags |= EDGE_FALLTHRU; + break; + } + delete_insn (jump); + } + return 1; } @@ -3049,11 +3068,11 @@ local_cprop_find_used_regs (rtx *xptr, void *data) find_used_regs (xptr, data); } -/* LIBCALL_SP is a zero-terminated array of insns at the end of a libcall; - their REG_EQUAL notes need updating. */ +/* Try to perform local const/copy propagation on X in INSN. + If ALTER_JUMPS is false, changing jump insns is not allowed. */ static bool -do_local_cprop (rtx x, rtx insn, bool alter_jumps, rtx *libcall_sp) +do_local_cprop (rtx x, rtx insn, bool alter_jumps) { rtx newreg = NULL, newcnst = NULL; @@ -3074,10 +3093,6 @@ do_local_cprop (rtx x, rtx insn, bool alter_jumps, rtx *libcall_sp) rtx this_rtx = l->loc; rtx note; - /* Don't CSE non-constant values out of libcall blocks. */ - if (l->in_libcall && ! CONSTANT_P (this_rtx)) - continue; - if (gcse_constant_p (this_rtx)) newcnst = this_rtx; if (REG_P (this_rtx) && REGNO (this_rtx) >= FIRST_PSEUDO_REGISTER @@ -3092,16 +3107,6 @@ do_local_cprop (rtx x, rtx insn, bool alter_jumps, rtx *libcall_sp) } if (newcnst && constprop_register (insn, x, newcnst, alter_jumps)) { - /* If we find a case where we can't fix the retval REG_EQUAL notes - match the new register, we either have to abandon this replacement - or fix delete_trivially_dead_insns to preserve the setting insn, - or make it delete the REG_EQUAL note, and fix up all passes that - require the REG_EQUAL note there. */ - bool adjusted; - - adjusted = adjust_libcall_notes (x, newcnst, insn, libcall_sp); - gcc_assert (adjusted); - if (dump_file != NULL) { fprintf (dump_file, "LOCAL CONST-PROP: Replacing reg %d in ", @@ -3116,7 +3121,6 @@ do_local_cprop (rtx x, rtx insn, bool alter_jumps, rtx *libcall_sp) } else if (newreg && newreg != x && try_replace_reg (x, newreg, insn)) { - adjust_libcall_notes (x, newreg, insn, libcall_sp); if (dump_file != NULL) { fprintf (dump_file, @@ -3131,47 +3135,6 @@ do_local_cprop (rtx x, rtx insn, bool alter_jumps, rtx *libcall_sp) return false; } -/* LIBCALL_SP is a zero-terminated array of insns at the end of a libcall; - their REG_EQUAL notes need updating to reflect that OLDREG has been - replaced with NEWVAL in INSN. Return true if all substitutions could - be made. */ -static bool -adjust_libcall_notes (rtx oldreg, rtx newval, rtx insn, rtx *libcall_sp) -{ - rtx end; - - while ((end = *libcall_sp++)) - { - rtx note = find_reg_equal_equiv_note (end); - - if (! note) - continue; - - if (REG_P (newval)) - { - if (reg_set_between_p (newval, PREV_INSN (insn), end)) - { - do - { - note = find_reg_equal_equiv_note (end); - if (! note) - continue; - if (reg_mentioned_p (newval, XEXP (note, 0))) - return false; - } - while ((end = *libcall_sp++)); - return true; - } - } - XEXP (note, 0) = simplify_replace_rtx (XEXP (note, 0), oldreg, newval); - df_notes_rescan (end); - insn = end; - } - return true; -} - -#define MAX_NESTED_LIBCALLS 9 - /* 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. */ @@ -3182,29 +3145,16 @@ local_cprop_pass (bool alter_jumps) basic_block bb; rtx insn; struct reg_use *reg_used; - rtx libcall_stack[MAX_NESTED_LIBCALLS + 1], *libcall_sp; bool changed = false; cselib_init (false); - libcall_sp = &libcall_stack[MAX_NESTED_LIBCALLS]; - *libcall_sp = 0; FOR_EACH_BB (bb) { FOR_BB_INSNS (bb, insn) { if (INSN_P (insn)) { - rtx note = find_reg_note (insn, REG_LIBCALL, NULL_RTX); - - if (note) - { - gcc_assert (libcall_sp != libcall_stack); - *--libcall_sp = XEXP (note, 0); - } - note = find_reg_note (insn, REG_RETVAL, NULL_RTX); - if (note) - libcall_sp++; - note = find_reg_equal_equiv_note (insn); + rtx note = find_reg_equal_equiv_note (insn); do { reg_use_count = 0; @@ -3216,8 +3166,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, - libcall_sp)) + if (do_local_cprop (reg_used->reg_rtx, insn, alter_jumps)) { changed = true; break; @@ -3231,10 +3180,8 @@ local_cprop_pass (bool alter_jumps) cselib_process_insn (insn); } - /* Forget everything at the end of a basic block. Make sure we are - not inside a libcall, they should never cross basic blocks. */ + /* Forget everything at the end of a basic block. */ cselib_clear_table (); - gcc_assert (libcall_sp == &libcall_stack[MAX_NESTED_LIBCALLS]); } cselib_finish (); @@ -3313,10 +3260,10 @@ fis_get_condition (rtx jump) it. COND is either an EQ or NE comparison. */ static bool -implicit_set_cond_p (rtx cond) +implicit_set_cond_p (const_rtx cond) { - enum machine_mode mode = GET_MODE (XEXP (cond, 0)); - rtx cst = XEXP (cond, 1); + const enum machine_mode mode = GET_MODE (XEXP (cond, 0)); + const_rtx cst = XEXP (cond, 1); /* We can't perform this optimization if either operand might be or might contain a signed zero. */ @@ -3353,7 +3300,7 @@ find_implicit_sets (void) { basic_block bb, dest; unsigned int count; - rtx cond, new; + rtx cond, new_rtx; count = 0; FOR_EACH_BB (bb) @@ -3374,9 +3321,9 @@ find_implicit_sets (void) if (dest && single_pred_p (dest) && dest != EXIT_BLOCK_PTR) { - new = gen_rtx_SET (VOIDmode, XEXP (cond, 0), + new_rtx = gen_rtx_SET (VOIDmode, XEXP (cond, 0), XEXP (cond, 1)); - implicit_sets[dest->index] = new; + implicit_sets[dest->index] = new_rtx; if (dump_file) { fprintf(dump_file, "Implicit set of reg %d in ", @@ -3504,7 +3451,7 @@ find_bypass_set (int regno, int bb) valid prior to commit_edge_insertions. */ static bool -reg_killed_on_edge (rtx reg, edge e) +reg_killed_on_edge (const_rtx reg, const_edge e) { rtx insn; @@ -3586,7 +3533,7 @@ bypass_block (basic_block bb, rtx setcc, rtx jump) unsigned int regno = REGNO (reg_used->reg_rtx); basic_block dest, old_dest; struct expr *set; - rtx src, new; + rtx src, new_rtx; if (regno >= max_gcse_regno) continue; @@ -3607,7 +3554,7 @@ bypass_block (basic_block bb, rtx setcc, rtx jump) SET_DEST (PATTERN (setcc)), SET_SRC (PATTERN (setcc))); - new = simplify_replace_rtx (src, reg_used->reg_rtx, + new_rtx = simplify_replace_rtx (src, reg_used->reg_rtx, SET_SRC (set->expr)); /* Jump bypassing may have already placed instructions on @@ -3615,14 +3562,14 @@ bypass_block (basic_block bb, rtx setcc, rtx jump) has instructions associated with it, as these insns won't get executed if the incoming edge is redirected. */ - if (new == pc_rtx) + if (new_rtx == pc_rtx) { edest = FALLTHRU_EDGE (bb); dest = edest->insns.r ? NULL : edest->dest; } - else if (GET_CODE (new) == LABEL_REF) + else if (GET_CODE (new_rtx) == LABEL_REF) { - dest = BLOCK_FOR_INSN (XEXP (new, 0)); + dest = BLOCK_FOR_INSN (XEXP (new_rtx, 0)); /* Don't bypass edges containing instructions. */ edest = find_edge (bb, dest); if (edest && edest->insns.r) @@ -4383,7 +4330,7 @@ pre_insert_copies (void) static rtx gcse_emit_move_after (rtx src, rtx dest, rtx insn) { - rtx new; + rtx new_rtx; rtx set = single_set (insn), set2; rtx note; rtx eqv; @@ -4391,20 +4338,20 @@ gcse_emit_move_after (rtx src, rtx dest, rtx insn) /* This should never fail since we're creating a reg->reg copy we've verified to be valid. */ - new = emit_insn_after (gen_move_insn (dest, src), insn); + new_rtx = emit_insn_after (gen_move_insn (dest, src), insn); /* Note the equivalence for local CSE pass. */ - set2 = single_set (new); + set2 = single_set (new_rtx); if (!set2 || !rtx_equal_p (SET_DEST (set2), dest)) - return new; + return new_rtx; if ((note = find_reg_equal_equiv_note (insn))) eqv = XEXP (note, 0); else eqv = SET_SRC (set); - set_unique_reg_note (new, REG_EQUAL, copy_insn_1 (eqv)); + set_unique_reg_note (new_rtx, REG_EQUAL, copy_insn_1 (eqv)); - return new; + return new_rtx; } /* Delete redundant computations. @@ -4448,8 +4395,7 @@ pre_delete (void) expressions into. Get the mode for the new pseudo from the mode of the original destination pseudo. */ if (expr->reaching_reg == NULL) - expr->reaching_reg - = gen_reg_rtx (GET_MODE (SET_DEST (set))); + expr->reaching_reg = gen_reg_rtx_and_attrs (SET_DEST (set)); gcse_emit_move_after (expr->reaching_reg, SET_DEST (set), insn); delete_insn (insn); @@ -4581,14 +4527,15 @@ one_pre_gcse_pass (int pass) return changed; } -/* If X contains any LABEL_REF's, add REG_LABEL notes for them to INSN. - If notes are added to an insn which references a CODE_LABEL, the - LABEL_NUSES count is incremented. We have to add REG_LABEL notes, - because the following loop optimization pass requires them. */ +/* If X contains any LABEL_REF's, add REG_LABEL_OPERAND notes for them + to INSN. If such notes are added to an insn which references a + CODE_LABEL, the LABEL_NUSES count is incremented. We have to add + that note, because the following loop optimization pass requires + them. */ /* ??? If there was a jump optimization pass after gcse and before loop, then we would not need to do this here, because jump would add the - necessary REG_LABEL notes. */ + necessary REG_LABEL_OPERAND and REG_LABEL_TARGET notes. */ static void add_label_notes (rtx x, rtx insn) @@ -4605,10 +4552,15 @@ add_label_notes (rtx x, rtx insn) We no longer ignore such label references (see LABEL_REF handling in mark_jump_label for additional information). */ - REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL, XEXP (x, 0), - REG_NOTES (insn)); + /* There's no reason for current users to emit jump-insns with + such a LABEL_REF, so we don't have to handle REG_LABEL_TARGET + notes. */ + gcc_assert (!JUMP_P (insn)); + add_reg_note (insn, REG_LABEL_OPERAND, XEXP (x, 0)); + if (LABEL_P (XEXP (x, 0))) LABEL_NUSES (XEXP (x, 0))++; + return; } @@ -4646,7 +4598,7 @@ compute_transpout (void) FOR_EACH_BB (bb) { - /* Note that flow inserted a nop a the end of basic blocks that + /* Note that flow inserted a nop at the end of basic blocks that end in call instructions for reasons other than abnormal control flow. */ if (! CALL_P (BB_END (bb))) @@ -4741,10 +4693,14 @@ compute_code_hoist_vbeinout (void) the convergence. */ FOR_EACH_BB_REVERSE (bb) { - changed |= sbitmap_a_or_b_and_c_cg (hoist_vbein[bb->index], antloc[bb->index], - hoist_vbeout[bb->index], transp[bb->index]); if (bb->next_bb != EXIT_BLOCK_PTR) - sbitmap_intersection_of_succs (hoist_vbeout[bb->index], hoist_vbein, bb->index); + sbitmap_intersection_of_succs (hoist_vbeout[bb->index], + hoist_vbein, bb->index); + + changed |= sbitmap_a_or_b_and_c_cg (hoist_vbein[bb->index], + antloc[bb->index], + hoist_vbeout[bb->index], + transp[bb->index]); } passes++; @@ -4962,7 +4918,7 @@ hoist_code (void) from the mode of the original destination pseudo. */ if (expr->reaching_reg == NULL) expr->reaching_reg - = gen_reg_rtx (GET_MODE (SET_DEST (set))); + = gen_reg_rtx_and_attrs (SET_DEST (set)); gcse_emit_move_after (expr->reaching_reg, SET_DEST (set), insn); delete_insn (insn); @@ -5038,14 +4994,15 @@ static hashval_t pre_ldst_expr_hash (const void *p) { int do_not_record_p = 0; - const struct ls_expr *x = p; + const struct ls_expr *const x = (const struct ls_expr *) p; return hash_rtx (x->pattern, GET_MODE (x->pattern), &do_not_record_p, NULL, false); } static int pre_ldst_expr_eq (const void *p1, const void *p2) { - const struct ls_expr *ptr1 = p1, *ptr2 = p2; + const struct ls_expr *const ptr1 = (const struct ls_expr *) p1, + *const ptr2 = (const struct ls_expr *) p2; return expr_equiv_p (ptr1->pattern, ptr2->pattern); } @@ -5167,7 +5124,7 @@ find_rtx_in_ldst (rtx x) slot = htab_find_slot (pre_ldst_table, &e, NO_INSERT); if (!slot || ((struct ls_expr *)*slot)->invalid) return NULL; - return *slot; + return (struct ls_expr *) *slot; } /* Assign each element of the list of mems a monotonically increasing value. */ @@ -5207,7 +5164,7 @@ next_ls_expr (struct ls_expr * ptr) ld_motion list, otherwise we let the usual aliasing take care of it. */ static int -simple_mem (rtx x) +simple_mem (const_rtx x) { if (! MEM_P (x)) return 0; @@ -5421,7 +5378,7 @@ update_ld_motion_stores (struct expr * expr) rtx pat = PATTERN (insn); rtx src = SET_SRC (pat); rtx reg = expr->reaching_reg; - rtx copy, new; + rtx copy, new_rtx; /* If we've already copied it, continue. */ if (expr->reaching_reg == src) @@ -5437,8 +5394,8 @@ update_ld_motion_stores (struct expr * expr) } copy = gen_move_insn ( reg, copy_rtx (SET_SRC (pat))); - new = emit_insn_before (copy, insn); - record_one_set (REGNO (reg), new); + new_rtx = emit_insn_before (copy, insn); + record_one_set (REGNO (reg), new_rtx); SET_SRC (pat) = reg; df_insn_rescan (insn); @@ -5472,10 +5429,10 @@ static int num_stores; note_stores. */ static void -reg_set_info (rtx dest, rtx setter ATTRIBUTE_UNUSED, +reg_set_info (rtx dest, const_rtx setter ATTRIBUTE_UNUSED, void *data) { - sbitmap bb_reg = data; + sbitmap bb_reg = (sbitmap) data; if (GET_CODE (dest) == SUBREG) dest = SUBREG_REG (dest); @@ -5492,10 +5449,10 @@ reg_set_info (rtx dest, rtx setter ATTRIBUTE_UNUSED, note_stores. */ static void -reg_clear_last_set (rtx dest, rtx setter ATTRIBUTE_UNUSED, +reg_clear_last_set (rtx dest, const_rtx setter ATTRIBUTE_UNUSED, void *data) { - int *dead_vec = data; + int *dead_vec = (int *) data; if (GET_CODE (dest) == SUBREG) dest = SUBREG_REG (dest); @@ -5509,9 +5466,9 @@ reg_clear_last_set (rtx dest, rtx setter ATTRIBUTE_UNUSED, due to set of registers in bitmap REGS_SET. */ static bool -store_ops_ok (rtx x, int *regs_set) +store_ops_ok (const_rtx x, int *regs_set) { - rtx reg; + const_rtx reg; for (; x; x = XEXP (x, 1)) { @@ -5569,6 +5526,7 @@ extract_mentioned_regs_helper (rtx x, rtx accum) case CONST: case CONST_INT: case CONST_DOUBLE: + case CONST_FIXED: case CONST_VECTOR: case SYMBOL_REF: case LABEL_REF: @@ -5865,7 +5823,7 @@ compute_store_table (void) after the X. */ static bool -load_kills_store (rtx x, rtx store_pattern, int after) +load_kills_store (const_rtx x, const_rtx store_pattern, int after) { if (after) return anti_dependence (x, store_pattern); @@ -5880,7 +5838,7 @@ load_kills_store (rtx x, rtx store_pattern, int after) after the insn X. */ static bool -find_loads (rtx x, rtx store_pattern, int after) +find_loads (const_rtx x, const_rtx store_pattern, int after) { const char * fmt; int i, j; @@ -5913,7 +5871,7 @@ find_loads (rtx x, rtx store_pattern, int after) } static inline bool -store_killed_in_pat (rtx x, rtx pat, int after) +store_killed_in_pat (const_rtx x, const_rtx pat, int after) { if (GET_CODE (pat) == SET) { @@ -5950,9 +5908,9 @@ store_killed_in_pat (rtx x, rtx pat, int after) after the insn. Return true if it does. */ static bool -store_killed_in_insn (rtx x, rtx x_regs, rtx insn, int after) +store_killed_in_insn (const_rtx x, const_rtx x_regs, const_rtx insn, int after) { - rtx reg, base, note, pat; + const_rtx reg, base, note, pat; if (!INSN_P (insn)) return false; @@ -5961,7 +5919,7 @@ store_killed_in_insn (rtx x, rtx x_regs, rtx insn, int after) { /* A normal or pure call might read from pattern, but a const call will not. */ - if (! CONST_OR_PURE_CALL_P (insn) || pure_call_p (insn)) + if (!RTL_CONST_CALL_P (insn)) return true; /* But even a const call reads its parameters. Check whether the @@ -6018,7 +5976,7 @@ store_killed_in_insn (rtx x, rtx x_regs, rtx insn, int after) is killed, return the last insn in that it occurs in FAIL_INSN. */ static bool -store_killed_after (rtx x, rtx x_regs, rtx insn, basic_block bb, +store_killed_after (const_rtx x, const_rtx x_regs, const_rtx insn, const_basic_block bb, int *regs_set_after, rtx *fail_insn) { rtx last = BB_END (bb), act; @@ -6047,7 +6005,7 @@ store_killed_after (rtx x, rtx x_regs, rtx insn, basic_block bb, within basic block BB. X_REGS is list of registers mentioned in X. REGS_SET_BEFORE is bitmap of registers set before or in this insn. */ static bool -store_killed_before (rtx x, rtx x_regs, rtx insn, basic_block bb, +store_killed_before (const_rtx x, const_rtx x_regs, const_rtx insn, const_basic_block bb, int *regs_set_before) { rtx first = BB_HEAD (bb); @@ -6094,7 +6052,7 @@ build_store_vectors (void) are any side effects. */ if (TEST_BIT (ae_gen[bb->index], ptr->index)) { - rtx r = gen_reg_rtx (GET_MODE (ptr->pattern)); + rtx r = gen_reg_rtx_and_attrs (ptr->pattern); if (dump_file) fprintf (dump_file, "Removing redundant store:\n"); replace_store_insn (r, XEXP (st, 0), bb, ptr); @@ -6337,21 +6295,10 @@ remove_reachable_equiv_notes (basic_block bb, struct ls_expr *smexpr) static void replace_store_insn (rtx reg, rtx del, basic_block bb, struct ls_expr *smexpr) { - rtx insn, mem, note, set, ptr, pair; + rtx insn, mem, note, set, ptr; mem = smexpr->pattern; insn = gen_move_insn (reg, SET_SRC (single_set (del))); - insn = emit_insn_after (insn, del); - - if (dump_file) - { - 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 "); - print_inline_rtx (dump_file, insn, 6); - fprintf (dump_file, "\n"); - } for (ptr = ANTIC_STORE_LIST (smexpr); ptr; ptr = XEXP (ptr, 1)) if (XEXP (ptr, 0) == del) @@ -6360,23 +6307,21 @@ replace_store_insn (rtx reg, rtx del, basic_block bb, struct ls_expr *smexpr) break; } - /* Move the notes from the deleted insn to its replacement, and patch - up the LIBCALL notes. */ + /* Move the notes from the deleted insn to its replacement. */ REG_NOTES (insn) = REG_NOTES (del); - note = find_reg_note (insn, REG_RETVAL, NULL_RTX); - if (note) - { - pair = XEXP (note, 0); - note = find_reg_note (pair, REG_LIBCALL, NULL_RTX); - XEXP (note, 0) = insn; - } - note = find_reg_note (insn, REG_LIBCALL, NULL_RTX); - if (note) + /* Emit the insn AFTER all the notes are transferred. + This is cheaper since we avoid df rescanning for the note change. */ + insn = emit_insn_after (insn, del); + + if (dump_file) { - pair = XEXP (note, 0); - note = find_reg_note (pair, REG_RETVAL, NULL_RTX); - XEXP (note, 0) = insn; + 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 "); + print_inline_rtx (dump_file, insn, 6); + fprintf (dump_file, "\n"); } delete_insn (del); @@ -6414,7 +6359,7 @@ delete_store (struct ls_expr * expr, basic_block bb) rtx reg, i, del; if (expr->reaching_reg == NULL_RTX) - expr->reaching_reg = gen_reg_rtx (GET_MODE (expr->pattern)); + expr->reaching_reg = gen_reg_rtx_and_attrs (expr->pattern); reg = expr->reaching_reg; @@ -6546,7 +6491,7 @@ bypass_jumps (void) /* We do not construct an accurate cfg in functions which call setjmp, so just punt to be safe. */ - if (current_function_calls_setjmp) + if (cfun->calls_setjmp) return 0; /* Identify the basic block information for this function, including @@ -6581,7 +6526,7 @@ bypass_jumps (void) max_gcse_regno = max_reg_num (); alloc_gcse_mem (); - changed = one_cprop_pass (MAX_GCSE_PASSES + 2, true, true); + changed = one_cprop_pass (3, true, true); free_gcse_mem (); if (dump_file) @@ -6643,7 +6588,8 @@ is_too_expensive (const char *pass) static bool gate_handle_jump_bypass (void) { - return optimize > 0 && flag_gcse; + return optimize > 0 && flag_gcse + && dbg_cnt (jump_bypass); } /* Perform jump bypassing and control flow optimizations. */ @@ -6660,8 +6606,10 @@ rest_of_handle_jump_bypass (void) return 0; } -struct tree_opt_pass pass_jump_bypass = +struct rtl_opt_pass pass_jump_bypass = { + { + RTL_PASS, "bypass", /* name */ gate_handle_jump_bypass, /* gate */ rest_of_handle_jump_bypass, /* execute */ @@ -6669,20 +6617,21 @@ struct tree_opt_pass pass_jump_bypass = NULL, /* next */ 0, /* static_pass_number */ TV_BYPASS, /* tv_id */ - 0, /* properties_required */ + PROP_cfglayout, /* properties_required */ 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ TODO_dump_func | - TODO_ggc_collect | TODO_verify_flow, /* todo_flags_finish */ - 'G' /* letter */ + TODO_ggc_collect | TODO_verify_flow /* todo_flags_finish */ + } }; static bool gate_handle_gcse (void) { - return optimize > 0 && flag_gcse; + return optimize > 0 && flag_gcse + && dbg_cnt (gcse); } @@ -6704,7 +6653,7 @@ rest_of_handle_gcse (void) { timevar_push (TV_CSE); tem2 = cse_main (get_insns (), max_reg_num ()); - df_finish_pass (); + df_finish_pass (false); purge_all_dead_edges (); delete_trivially_dead_insns (get_insns (), max_reg_num ()); timevar_pop (TV_CSE); @@ -6713,21 +6662,25 @@ rest_of_handle_gcse (void) /* If gcse or cse altered any jumps, rerun jump optimizations to clean things up. */ - if (tem || tem2) + 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; } -struct tree_opt_pass pass_gcse = +struct rtl_opt_pass pass_gcse = { + { + RTL_PASS, "gcse1", /* name */ gate_handle_gcse, /* gate */ rest_of_handle_gcse, /* execute */ @@ -6735,14 +6688,14 @@ struct tree_opt_pass pass_gcse = NULL, /* next */ 0, /* static_pass_number */ TV_GCSE, /* tv_id */ - 0, /* properties_required */ + PROP_cfglayout, /* properties_required */ 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ - TODO_df_finish | + TODO_df_finish | TODO_verify_rtl_sharing | TODO_dump_func | - TODO_verify_flow | TODO_ggc_collect, /* todo_flags_finish */ - 'G' /* letter */ + TODO_verify_flow | TODO_ggc_collect /* todo_flags_finish */ + } };