X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Fgcse.c;h=db7e03c03d9f45a97bb52361e0f1e220404bdcab;hp=10460a8f32f63ffbcb94b0483b681a2fac55b78f;hb=5c6d2374f58e4e2944643b231a90a85c19b296aa;hpb=c3ceba8e8139354ec6e7fb9510bb3541d5baac23 diff --git a/gcc/gcse.c b/gcc/gcse.c index 10460a8f32f..db7e03c03d9 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 - Free Software Foundation, Inc. + Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, + 2006, 2007 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, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ +along with GCC; see the file COPYING3. If not see +. */ /* TODO - reordering of memory allocation and freeing to be more space efficient @@ -169,6 +168,10 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "intl.h" #include "obstack.h" #include "timevar.h" +#include "tree-pass.h" +#include "hashtab.h" +#include "df.h" +#include "dbgcnt.h" /* Propagate flow information through back edges and thus enable PRE's moving loop invariant calculations out of loops. @@ -269,9 +272,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA /* GCSE global vars. */ -/* -dG dump file. */ -static FILE *gcse_file; - /* Note whether or not we should run jump optimization after gcse. We want to do this for two cases. @@ -280,13 +280,6 @@ static FILE *gcse_file; * If we added any labels via edge splitting. */ static int run_jump_opt_after_gcse; -/* Bitmaps are normally not included in debugging dumps. - However it's useful to be able to print them from GDB. - We could create special functions for this, but it's simpler to - just allow passing stderr to the dump_foo fns. Since stderr can - be a macro, we store a copy here. */ -static FILE *debug_stderr; - /* An obstack for our working variables. */ static struct obstack gcse_obstack; @@ -387,12 +380,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. */ @@ -470,6 +457,9 @@ static rtx *implicit_sets; /* Head of the list of load/store memory refs. */ static struct ls_expr * pre_ldst_mems = NULL; +/* Hashtable for the load/store memory refs. */ +static htab_t pre_ldst_table = NULL; + /* Bitmap containing one bit for each register in the program. Used when performing GCSE to track which registers have been set since the start of the basic block. */ @@ -507,11 +497,11 @@ static int gcse_subst_count; static int gcse_create_count; /* Number of local constants propagated. */ static int local_const_prop_count; -/* Number of local copys propagated. */ +/* Number of local copies propagated. */ static int local_copy_prop_count; /* Number of global constants propagated. */ static int global_const_prop_count; -/* Number of global copys propagated. */ +/* Number of global copies propagated. */ static int global_copy_prop_count; /* For available exprs */ @@ -527,7 +517,7 @@ 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_set (rtx, rtx, struct hash_table *); @@ -535,19 +525,19 @@ 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 *); @@ -556,14 +546,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 *); @@ -572,16 +562,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); @@ -589,7 +579,7 @@ static void free_pre_mem (void); static void compute_pre_data (void); static int pre_expr_reaches_here_p (basic_block, struct expr *, basic_block); -static void insert_insn_end_bb (struct expr *, basic_block, int); +static void insert_insn_end_basic_block (struct expr *, basic_block, int); static void pre_insert_copy_insn (struct expr *, rtx); static void pre_insert_copies (void); static int pre_delete (void); @@ -615,25 +605,25 @@ 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_bb (rtx, basic_block); +static void insert_insn_start_basic_block (rtx, basic_block); static int insert_store (struct ls_expr *, edge); static void remove_reachable_equiv_notes (basic_block, struct ls_expr *); static void replace_store_insn (rtx, rtx, basic_block, struct ls_expr *); @@ -655,8 +645,8 @@ static bool is_too_expensive (const char *); F is the first instruction in the function. Return nonzero if a change is mode. */ -int -gcse_main (rtx f ATTRIBUTE_UNUSED, FILE *file) +static int +gcse_main (rtx f ATTRIBUTE_UNUSED) { int changed, pass; /* Bytes used at start of pass. */ @@ -674,19 +664,19 @@ gcse_main (rtx f ATTRIBUTE_UNUSED, FILE *file) /* Assume that we do not need to run jump optimizations after gcse. */ run_jump_opt_after_gcse = 0; - /* For calling dump_foo fns from gdb. */ - debug_stderr = stderr; - gcse_file = file; - /* Identify the basic block information for this function, including successors and predecessors. */ max_gcse_regno = max_reg_num (); - if (file) - dump_flow_info (file); + 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 <= 1 || is_too_expensive (_("GCSE disabled"))) + if (n_basic_blocks <= NUM_FIXED_BLOCKS + 1 + || is_too_expensive (_("GCSE disabled"))) return 0; gcc_obstack_init (&gcse_obstack); @@ -714,8 +704,8 @@ gcse_main (rtx f ATTRIBUTE_UNUSED, FILE *file) while (changed && pass < MAX_GCSE_PASSES) { changed = 0; - if (file) - fprintf (file, "GCSE pass %d\n\n", pass + 1); + 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. */ @@ -780,10 +770,10 @@ gcse_main (rtx f ATTRIBUTE_UNUSED, FILE *file) timevar_pop (TV_HOIST); } - if (file) + if (dump_file) { - fprintf (file, "\n"); - fflush (file); + fprintf (dump_file, "\n"); + fflush (dump_file); } obstack_free (&gcse_obstack, gcse_obstack_bottom); @@ -797,15 +787,15 @@ gcse_main (rtx f ATTRIBUTE_UNUSED, FILE *file) alloc_gcse_mem (); /* This time, go ahead and allow cprop to alter jumps. */ timevar_push (TV_CPROP2); - one_cprop_pass (pass + 1, true, false); + one_cprop_pass (pass + 1, true, true); timevar_pop (TV_CPROP2); free_gcse_mem (); - if (file) + if (dump_file) { - fprintf (file, "GCSE of %s: %d basic blocks, ", + fprintf (dump_file, "GCSE of %s: %d basic blocks, ", current_function_name (), n_basic_blocks); - fprintf (file, "%d pass%s, %d bytes\n\n", + fprintf (dump_file, "%d pass%s, %d bytes\n\n", pass, pass > 1 ? "es" : "", max_pass_bytes); } @@ -814,7 +804,6 @@ gcse_main (rtx f ATTRIBUTE_UNUSED, FILE *file) /* We are finished with alias. */ end_alias_analysis (); - allocate_reg_info (max_reg_num (), FALSE, FALSE); if (!optimize_size && flag_gcse_sm) { @@ -947,15 +936,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); @@ -976,7 +957,6 @@ static void free_gcse_mem (void) { free (uid_cuid); - free (cuid_insn); BITMAP_FREE (reg_set_bitmap); @@ -1134,7 +1114,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; @@ -1178,12 +1158,21 @@ static basic_block current_bb; static int want_to_gcse_p (rtx x) { +#ifdef STACK_REGS + /* On register stack architectures, don't GCSE constants from the + constant pool, as the benefits are often swamped by the overhead + of shuffling the register stack between basic blocks. */ + if (IS_STACK_MODE (GET_MODE (x))) + x = avoid_constant_pool_reference (x); +#endif + switch (GET_CODE (x)) { case REG: case SUBREG: case CONST_INT: case CONST_DOUBLE: + case CONST_FIXED: case CONST_VECTOR: case CALL: return 0; @@ -1236,7 +1225,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; @@ -1280,6 +1269,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: @@ -1322,14 +1312,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 @@ -1367,9 +1357,14 @@ 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]; + + /* If this is a readonly then we aren't going to be changing it. */ + if (MEM_READONLY_P (x)) + return 0; + while (list_entry) { rtx setter; @@ -1410,7 +1405,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); } @@ -1419,7 +1414,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); } @@ -1432,7 +1427,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; @@ -1463,7 +1458,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); } @@ -1652,7 +1647,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 @@ -1690,10 +1685,15 @@ hash_scan_set (rtx pat, rtx insn, struct hash_table *table) unsigned int regno = REGNO (dest); rtx tmp; - /* If this is a single set and we are doing constant propagation, - see if a REG_NOTE shows this equivalent to a constant. */ - if (table->set_p && (note = find_reg_equal_equiv_note (insn)) != 0 - && gcse_constant_p (XEXP (note, 0))) + /* See if a REG_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. */ + note = find_reg_equal_equiv_note (insn); + if (note != 0 + && (table->set_p + ? gcse_constant_p (XEXP (note, 0)) + : want_to_gcse_p (XEXP (note, 0)))) src = XEXP (note, 0), pat = gen_rtx_SET (VOIDmode, dest, src); /* Only record sets of pseudo-regs in the hash table. */ @@ -1714,13 +1714,15 @@ hash_scan_set (rtx pat, rtx insn, struct hash_table *table) REG_EQUIV notes and if the argument slot is used somewhere explicitly, it means address of parameter has been taken, so we should not extend the lifetime of the pseudo. */ - && ((note = find_reg_note (insn, REG_EQUIV, NULL_RTX)) == 0 - || ! MEM_P (XEXP (note, 0)))) + && (note == NULL_RTX || ! MEM_P (XEXP (note, 0)))) { /* An expression is not anticipatable if its operands are modified before this insn or if this is not the only SET in - this insn. */ - int antic_p = oprs_anticipatable_p (src, insn) && single_set (insn); + this insn. The latter condition does not have to mean that + SRC itself is not anticipatable, but we just will not be + able to handle code motion of insns with multiple sets. */ + int antic_p = oprs_anticipatable_p (src, insn) + && !multiple_sets (insn); /* An expression is not available if its operands are subsequently modified, including this insn. It's also not available if this is a branch, because we can't insert @@ -1743,8 +1745,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 @@ -1925,7 +1928,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; @@ -1986,7 +1989,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; @@ -2233,7 +2236,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; @@ -2250,6 +2253,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: @@ -2411,7 +2415,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; @@ -2462,51 +2466,53 @@ compute_transp (rtx x, int indx, sbitmap *bmap, int set_p) return; case MEM: - { - bitmap_iterator bi; - unsigned bb_index; - - /* First handle all the blocks with calls. We don't need to - do any list walking for them. */ - EXECUTE_IF_SET_IN_BITMAP (blocks_with_calls, 0, bb_index, bi) - { - if (set_p) - SET_BIT (bmap[bb_index], indx); - else - RESET_BIT (bmap[bb_index], indx); - } + if (! MEM_READONLY_P (x)) + { + bitmap_iterator bi; + unsigned bb_index; - /* Now iterate over the blocks which have memory modifications - but which do not have any calls. */ - EXECUTE_IF_AND_COMPL_IN_BITMAP (modify_mem_list_set, blocks_with_calls, - 0, bb_index, bi) - { - rtx list_entry = canon_modify_mem_list[bb_index]; + /* First handle all the blocks with calls. We don't need to + do any list walking for them. */ + EXECUTE_IF_SET_IN_BITMAP (blocks_with_calls, 0, bb_index, bi) + { + if (set_p) + SET_BIT (bmap[bb_index], indx); + else + RESET_BIT (bmap[bb_index], indx); + } - while (list_entry) + /* Now iterate over the blocks which have memory modifications + but which do not have any calls. */ + EXECUTE_IF_AND_COMPL_IN_BITMAP (modify_mem_list_set, + blocks_with_calls, + 0, bb_index, bi) { - rtx dest, dest_addr; + rtx list_entry = canon_modify_mem_list[bb_index]; - /* LIST_ENTRY must be an INSN of some kind that sets memory. - Examine each hunk of memory that is modified. */ + while (list_entry) + { + rtx dest, dest_addr; - dest = XEXP (list_entry, 0); - list_entry = XEXP (list_entry, 1); - dest_addr = XEXP (list_entry, 0); + /* LIST_ENTRY must be an INSN of some kind that sets memory. + Examine each hunk of memory that is modified. */ - if (canon_true_dependence (dest, GET_MODE (dest), dest_addr, - x, rtx_addr_varies_p)) - { - if (set_p) - SET_BIT (bmap[bb_index], indx); - else - RESET_BIT (bmap[bb_index], indx); - break; - } - list_entry = XEXP (list_entry, 1); + dest = XEXP (list_entry, 0); + list_entry = XEXP (list_entry, 1); + dest_addr = XEXP (list_entry, 0); + + if (canon_true_dependence (dest, GET_MODE (dest), dest_addr, + x, rtx_addr_varies_p)) + { + if (set_p) + SET_BIT (bmap[bb_index], indx); + else + RESET_BIT (bmap[bb_index], indx); + break; + } + list_entry = XEXP (list_entry, 1); + } } - } - } + } x = XEXP (x, 0); goto repeat; @@ -2516,6 +2522,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: @@ -2636,6 +2643,11 @@ try_replace_reg (rtx from, rtx to, rtx insn) int success = 0; rtx set = single_set (insn); + /* Usually we substitute easy stuff, so we won't copy everything. + We however need to take care to not duplicate non-trivial CONST + expressions. */ + to = copy_rtx (to); + validate_replace_src_group (from, to, insn); if (num_changes_pending () && apply_change_group ()) success = 1; @@ -2649,11 +2661,12 @@ try_replace_reg (rtx from, rtx to, rtx insn) validate_change (insn, &SET_SRC (set), src, 0); } - /* If there is already a NOTE, update the expression in it with our - replacement. */ - if (note != 0) - XEXP (note, 0) = simplify_replace_rtx (XEXP (note, 0), from, to); - + /* If there is already a REG_EQUAL note, update the expression in it + 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, + 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 @@ -2669,7 +2682,8 @@ try_replace_reg (rtx from, rtx to, rtx insn) have a note, and have no special SET, add a REG_EQUAL note to not lose information. */ if (!success && note == 0 && set != 0 - && GET_CODE (SET_DEST (set)) != ZERO_EXTRACT) + && GET_CODE (SET_DEST (set)) != ZERO_EXTRACT + && GET_CODE (SET_DEST (set)) != STRICT_LOW_PART) note = set_unique_reg_note (insn, REG_EQUAL, copy_rtx (src)); } @@ -2677,7 +2691,7 @@ try_replace_reg (rtx from, rtx to, rtx insn) We don't allow that. Remove that note. This code ought not to happen, because previous code ought to synthesize reg-reg move, but be on the safe side. */ - if (note && REG_P (XEXP (note, 0))) + if (note && REG_NOTE_KIND (note) == REG_EQUAL && REG_P (XEXP (note, 0))) remove_note (insn, note); return success; @@ -2826,12 +2840,6 @@ cprop_jump (basic_block bb, rtx setcc, rtx jump, rtx from, rtx src) /* Remove REG_EQUAL note after simplification. */ if (note_src) remove_note (jump, note); - - /* If this has turned into an unconditional jump, - then put a barrier after it so that the unreachable - code will be deleted. */ - if (GET_CODE (SET_SRC (set)) == LABEL_REF) - emit_barrier_after (jump); } #ifdef HAVE_cc0 @@ -2843,16 +2851,34 @@ cprop_jump (basic_block bb, rtx setcc, rtx jump, rtx from, rtx src) run_jump_opt_after_gcse = 1; global_const_prop_count++; - if (gcse_file != NULL) + if (dump_file != NULL) { - fprintf (gcse_file, + fprintf (dump_file, "GLOBAL CONST-PROP: Replacing reg %d in jump_insn %d with constant ", REGNO (from), INSN_UID (jump)); - print_rtl (gcse_file, src); - fprintf (gcse_file, "\n"); + print_rtl (dump_file, src); + fprintf (dump_file, "\n"); } 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 != 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; } @@ -2948,12 +2974,12 @@ cprop_insn (rtx insn, int alter_jumps) { changed = 1; global_const_prop_count++; - if (gcse_file != NULL) + if (dump_file != NULL) { - fprintf (gcse_file, "GLOBAL CONST-PROP: Replacing reg %d in ", regno); - fprintf (gcse_file, "insn %d with constant ", INSN_UID (insn)); - print_rtl (gcse_file, src); - fprintf (gcse_file, "\n"); + fprintf (dump_file, "GLOBAL CONST-PROP: Replacing reg %d in ", regno); + fprintf (dump_file, "insn %d with constant ", INSN_UID (insn)); + print_rtl (dump_file, src); + fprintf (dump_file, "\n"); } if (INSN_DELETED_P (insn)) return 1; @@ -2967,11 +2993,11 @@ cprop_insn (rtx insn, int alter_jumps) { changed = 1; global_copy_prop_count++; - if (gcse_file != NULL) + if (dump_file != NULL) { - fprintf (gcse_file, "GLOBAL COPY-PROP: Replacing reg %d in insn %d", + fprintf (dump_file, "GLOBAL COPY-PROP: Replacing reg %d in insn %d", regno, INSN_UID (insn)); - fprintf (gcse_file, " with reg %d\n", REGNO (src)); + fprintf (dump_file, " with reg %d\n", REGNO (src)); } /* The original insn setting reg_used may or may not now be @@ -3077,21 +3103,21 @@ do_local_cprop (rtx x, rtx insn, bool alter_jumps, rtx *libcall_sp) /* 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_EUAQL note, and fix up all passes that + 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 (gcse_file != NULL) + if (dump_file != NULL) { - fprintf (gcse_file, "LOCAL CONST-PROP: Replacing reg %d in ", + fprintf (dump_file, "LOCAL CONST-PROP: Replacing reg %d in ", REGNO (x)); - fprintf (gcse_file, "insn %d with constant ", + fprintf (dump_file, "insn %d with constant ", INSN_UID (insn)); - print_rtl (gcse_file, newcnst); - fprintf (gcse_file, "\n"); + print_rtl (dump_file, newcnst); + fprintf (dump_file, "\n"); } local_const_prop_count++; return true; @@ -3099,12 +3125,12 @@ 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 (gcse_file != NULL) + if (dump_file != NULL) { - fprintf (gcse_file, + fprintf (dump_file, "LOCAL COPY-PROP: Replacing reg %d in insn %d", REGNO (x), INSN_UID (insn)); - fprintf (gcse_file, " with reg %d\n", REGNO (newreg)); + fprintf (dump_file, " with reg %d\n", REGNO (newreg)); } local_copy_prop_count++; return true; @@ -3146,6 +3172,7 @@ adjust_libcall_notes (rtx oldreg, rtx newval, rtx insn, rtx *libcall_sp) } } XEXP (note, 0) = simplify_replace_rtx (XEXP (note, 0), oldreg, newval); + df_notes_rescan (end); insn = end; } return true; @@ -3196,12 +3223,14 @@ 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)) - { - changed = true; - break; - } + { + if (do_local_cprop (reg_used->reg_rtx, insn, alter_jumps, + libcall_sp)) + { + changed = true; + break; + } + } if (INSN_DELETED_P (insn)) break; } @@ -3241,8 +3270,8 @@ cprop (int alter_jumps) /* Note we start at block 1. */ if (ENTRY_BLOCK_PTR->next_bb == EXIT_BLOCK_PTR) { - if (gcse_file != NULL) - fprintf (gcse_file, "\n"); + if (dump_file != NULL) + fprintf (dump_file, "\n"); return 0; } @@ -3266,8 +3295,8 @@ cprop (int alter_jumps) } } - if (gcse_file != NULL) - fprintf (gcse_file, "\n"); + if (dump_file != NULL) + fprintf (dump_file, "\n"); return changed; } @@ -3292,10 +3321,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. */ @@ -3356,19 +3385,19 @@ find_implicit_sets (void) new = gen_rtx_SET (VOIDmode, XEXP (cond, 0), XEXP (cond, 1)); implicit_sets[dest->index] = new; - if (gcse_file) + if (dump_file) { - fprintf(gcse_file, "Implicit set of reg %d in ", + fprintf(dump_file, "Implicit set of reg %d in ", REGNO (XEXP (cond, 0))); - fprintf(gcse_file, "basic block %d\n", dest->index); + fprintf(dump_file, "basic block %d\n", dest->index); } count++; } } } - if (gcse_file) - fprintf (gcse_file, "Found %d implicit sets\n", count); + if (dump_file) + fprintf (dump_file, "Found %d implicit sets\n", count); } /* Perform one copy/constant propagation pass. @@ -3384,10 +3413,11 @@ one_cprop_pass (int pass, bool cprop_jumps, bool bypass_jumps) global_const_prop_count = local_const_prop_count = 0; global_copy_prop_count = local_copy_prop_count = 0; - local_cprop_pass (cprop_jumps); + if (cprop_jumps) + local_cprop_pass (cprop_jumps); /* Determine implicit sets. */ - implicit_sets = xcalloc (last_basic_block, sizeof (rtx)); + implicit_sets = XCNEWVEC (rtx, last_basic_block); find_implicit_sets (); alloc_hash_table (max_cuid, &set_hash_table, 1); @@ -3397,8 +3427,8 @@ one_cprop_pass (int pass, bool cprop_jumps, bool bypass_jumps) free (implicit_sets); implicit_sets = NULL; - if (gcse_file) - dump_hash_table (gcse_file, "SET", &set_hash_table); + 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); @@ -3411,13 +3441,13 @@ one_cprop_pass (int pass, bool cprop_jumps, bool bypass_jumps) free_hash_table (&set_hash_table); - if (gcse_file) + if (dump_file) { - fprintf (gcse_file, "CPROP of %s, pass %d: %d bytes needed, ", + fprintf (dump_file, "CPROP of %s, pass %d: %d bytes needed, ", current_function_name (), pass, bytes_used); - fprintf (gcse_file, "%d local const props, %d local copy props\n\n", + fprintf (dump_file, "%d local const props, %d local copy props, ", local_const_prop_count, local_copy_prop_count); - fprintf (gcse_file, "%d global const props, %d global copy props\n\n", + 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. */ @@ -3482,7 +3512,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; @@ -3633,13 +3663,13 @@ bypass_block (basic_block bb, rtx setcc, rtx jump) insert_insn_on_edge (copy_insn (pat), e); } - if (gcse_file != NULL) + if (dump_file != NULL) { - fprintf (gcse_file, "JUMP-BYPASS: Proved reg %d " + fprintf (dump_file, "JUMP-BYPASS: Proved reg %d " "in jump_insn %d equals constant ", regno, INSN_UID (jump)); - print_rtl (gcse_file, SET_SRC (set->expr)); - fprintf (gcse_file, "\nBypass edge from %d->%d to %d\n", + print_rtl (dump_file, SET_SRC (set->expr)); + fprintf (dump_file, "\nBypass edge from %d->%d to %d\n", e->src->index, old_dest->index, dest->index); } change = 1; @@ -3713,7 +3743,7 @@ bypass_conditional_jumps (void) /* If we bypassed any register setting insns, we inserted a copy on the redirected edge. These need to be committed. */ if (changed) - commit_edge_insertions(); + commit_edge_insertions (); return changed; } @@ -3844,7 +3874,7 @@ compute_pre_data (void) sbitmap_not (ae_kill[bb->index], ae_kill[bb->index]); } - edge_list = pre_edge_lcm (gcse_file, expr_hash_table.n_elems, transp, comp, antloc, + edge_list = pre_edge_lcm (expr_hash_table.n_elems, transp, comp, antloc, ae_kill, &pre_insert_map, &pre_delete_map); sbitmap_vector_free (antloc); antloc = NULL; @@ -3918,7 +3948,7 @@ static int pre_expr_reaches_here_p (basic_block occr_bb, struct expr *expr, basic_block bb) { int rval; - char *visited = xcalloc (last_basic_block, 1); + char *visited = XCNEWVEC (char, last_basic_block); rval = pre_expr_reaches_here_p_work (occr_bb, expr, bb, visited); @@ -3972,7 +4002,7 @@ process_insert_insn (struct expr *expr) no sense for code hoisting. */ static void -insert_insn_end_bb (struct expr *expr, basic_block bb, int pre) +insert_insn_end_basic_block (struct expr *expr, basic_block bb, int pre) { rtx insn = BB_END (bb); rtx new_insn; @@ -4029,7 +4059,7 @@ insert_insn_end_bb (struct expr *expr, basic_block bb, int pre) } #endif /* FIXME: What if something in cc0/jump uses value set in new insn? */ - new_insn = emit_insn_before_noloc (pat, insn); + new_insn = emit_insn_before_noloc (pat, insn, bb); } /* Likewise if the last insn is a call, as will happen in the presence @@ -4068,10 +4098,10 @@ insert_insn_end_bb (struct expr *expr, basic_block bb, int pre) || NOTE_INSN_BASIC_BLOCK_P (insn)) insn = NEXT_INSN (insn); - new_insn = emit_insn_before_noloc (pat, insn); + new_insn = emit_insn_before_noloc (pat, insn, bb); } else - new_insn = emit_insn_after_noloc (pat, insn); + new_insn = emit_insn_after_noloc (pat, insn, bb); while (1) { @@ -4087,11 +4117,11 @@ insert_insn_end_bb (struct expr *expr, basic_block bb, int pre) gcse_create_count++; - if (gcse_file) + if (dump_file) { - fprintf (gcse_file, "PRE/HOIST: end of bb %d, insn %d, ", + fprintf (dump_file, "PRE/HOIST: end of bb %d, insn %d, ", bb->index, INSN_UID (new_insn)); - fprintf (gcse_file, "copying expression %d to reg %d\n", + fprintf (dump_file, "copying expression %d to reg %d\n", expr->bitmap_index, regno); } } @@ -4149,19 +4179,19 @@ pre_edge_insert (struct edge_list *edge_list, struct expr **index_map) now. */ if (eg->flags & EDGE_ABNORMAL) - insert_insn_end_bb (index_map[j], bb, 0); + insert_insn_end_basic_block (index_map[j], bb, 0); else { insn = process_insert_insn (index_map[j]); insert_insn_on_edge (insn, eg); } - if (gcse_file) + if (dump_file) { - fprintf (gcse_file, "PRE/HOIST: edge (%d,%d), ", + fprintf (dump_file, "PRE/HOIST: edge (%d,%d), ", bb->index, INDEX_EDGE_SUCC_BB (edge_list, e)->index); - fprintf (gcse_file, "copy expression %d\n", + fprintf (dump_file, "copy expression %d\n", expr->bitmap_index); } @@ -4201,7 +4231,7 @@ pre_insert_copy_insn (struct expr *expr, rtx insn) int regno = REGNO (reg); int indx = expr->bitmap_index; rtx pat = PATTERN (insn); - rtx set, new_insn; + rtx set, first_set, new_insn; rtx old_reg; int i; @@ -4215,17 +4245,29 @@ pre_insert_copy_insn (struct expr *expr, rtx insn) case PARALLEL: /* Search through the parallel looking for the set whose source was the expression that we're interested in. */ + first_set = NULL_RTX; set = NULL_RTX; for (i = 0; i < XVECLEN (pat, 0); i++) { rtx x = XVECEXP (pat, 0, i); - if (GET_CODE (x) == SET - && expr_equiv_p (SET_SRC (x), expr->expr)) + if (GET_CODE (x) == SET) { - set = x; - break; + /* If the source was a REG_EQUAL or REG_EQUIV note, we + may not find an equivalent expression, but in this + case the PARALLEL will have a single set. */ + if (first_set == NULL_RTX) + first_set = x; + if (expr_equiv_p (SET_SRC (x), expr->expr)) + { + set = x; + break; + } } } + + gcc_assert (first_set); + if (set == NULL_RTX) + set = first_set; break; default: @@ -4270,8 +4312,8 @@ pre_insert_copy_insn (struct expr *expr, rtx insn) gcse_create_count++; - if (gcse_file) - fprintf (gcse_file, + if (dump_file) + fprintf (dump_file, "PRE: bb %d, insn %d, copy expression %d in insn %d to reg %d\n", BLOCK_NUM (insn), INSN_UID (new_insn), indx, INSN_UID (insn), regno); @@ -4407,7 +4449,8 @@ pre_delete (void) /* We only delete insns that have a single_set. */ if (TEST_BIT (pre_delete_map[bb->index], indx) - && (set = single_set (insn)) != 0) + && (set = single_set (insn)) != 0 + && dbg_cnt (pre_insn)) { /* Create a pseudo-reg to store the result of reaching expressions into. Get the mode for the new pseudo from @@ -4423,12 +4466,12 @@ pre_delete (void) changed = 1; gcse_subst_count++; - if (gcse_file) + if (dump_file) { - fprintf (gcse_file, + fprintf (dump_file, "PRE: redundant insn %d (expression %d) in ", INSN_UID (insn), indx); - fprintf (gcse_file, "bb %d, reaching reg is %d\n", + fprintf (dump_file, "bb %d, reaching reg is %d\n", bb->index, REGNO (expr->reaching_reg)); } } @@ -4469,7 +4512,7 @@ pre_gcse (void) /* Compute a mapping from expression number (`bitmap_index') to hash table entry. */ - index_map = xcalloc (expr_hash_table.n_elems, sizeof (struct expr *)); + index_map = XCNEWVEC (struct expr *, expr_hash_table.n_elems); for (i = 0; i < expr_hash_table.size; i++) for (expr = expr_hash_table.table[i]; expr != NULL; expr = expr->next_same_hash) index_map[expr->bitmap_index] = expr; @@ -4484,7 +4527,6 @@ pre_gcse (void) - we know which insns are redundant when we go to create copies */ changed = pre_delete (); - did_insert = pre_edge_insert (edge_list, index_map); /* In other places with reaching expressions, copy the expression to the @@ -4520,8 +4562,8 @@ one_pre_gcse_pass (int pass) compute_hash_table (&expr_hash_table); trim_ld_motion_mems (); - if (gcse_file) - dump_hash_table (gcse_file, "Expression", &expr_hash_table); + if (dump_file) + dump_hash_table (dump_file, "Expression", &expr_hash_table); if (expr_hash_table.n_elems > 0) { @@ -4536,28 +4578,26 @@ one_pre_gcse_pass (int pass) remove_fake_exit_edges (); free_hash_table (&expr_hash_table); - if (gcse_file) + if (dump_file) { - fprintf (gcse_file, "\nPRE GCSE of %s, pass %d: %d bytes needed, ", + fprintf (dump_file, "\nPRE GCSE of %s, pass %d: %d bytes needed, ", current_function_name (), pass, bytes_used); - fprintf (gcse_file, "%d substs, %d insns created\n", + fprintf (dump_file, "%d substs, %d insns created\n", gcse_subst_count, gcse_create_count); } 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. */ - -/* ??? This is very similar to the loop.c add_label_notes function. We - could probably share code here. */ +/* 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) @@ -4574,10 +4614,16 @@ 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)); + REG_NOTES (insn) + = gen_rtx_INSN_LIST (REG_LABEL_OPERAND, XEXP (x, 0), + REG_NOTES (insn)); if (LABEL_P (XEXP (x, 0))) LABEL_NUSES (XEXP (x, 0))++; + return; } @@ -4710,17 +4756,21 @@ 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++; } - if (gcse_file) - fprintf (gcse_file, "hoisting vbeinout computation: %d passes\n", passes); + if (dump_file) + fprintf (dump_file, "hoisting vbeinout computation: %d passes\n", passes); } /* Top level routine to do the dataflow analysis needed by code hoisting. */ @@ -4732,8 +4782,8 @@ compute_code_hoist_data (void) compute_transpout (); compute_code_hoist_vbeinout (); calculate_dominance_info (CDI_DOMINATORS); - if (gcse_file) - fprintf (gcse_file, "\n"); + if (dump_file) + fprintf (dump_file, "\n"); } /* Determine if the expression identified by EXPR_INDEX would @@ -4760,7 +4810,7 @@ hoist_expr_reaches_here_p (basic_block expr_bb, int expr_index, basic_block bb, if (visited == NULL) { visited_allocated_locally = 1; - visited = xcalloc (last_basic_block, 1); + visited = XCNEWVEC (char, last_basic_block); } FOR_EACH_EDGE (pred, ei, bb->preds) @@ -4801,8 +4851,7 @@ static void hoist_code (void) { basic_block bb, dominated; - basic_block *domby; - unsigned int domby_len; + VEC (basic_block, heap) *domby; unsigned int i,j; struct expr **index_map; struct expr *expr; @@ -4812,7 +4861,7 @@ hoist_code (void) /* Compute a mapping from expression number (`bitmap_index') to hash table entry. */ - index_map = xcalloc (expr_hash_table.n_elems, sizeof (struct expr *)); + index_map = XCNEWVEC (struct expr *, expr_hash_table.n_elems); for (i = 0; i < expr_hash_table.size; i++) for (expr = expr_hash_table.table[i]; expr != NULL; expr = expr->next_same_hash) index_map[expr->bitmap_index] = expr; @@ -4824,7 +4873,7 @@ hoist_code (void) int found = 0; int insn_inserted_p; - domby_len = get_dominated_by (CDI_DOMINATORS, bb, &domby); + domby = get_dominated_by (CDI_DOMINATORS, bb); /* Examine each expression that is very busy at the exit of this block. These are the potentially hoistable expressions. */ for (i = 0; i < hoist_vbeout[bb->index]->n_bits; i++) @@ -4837,9 +4886,8 @@ hoist_code (void) /* We've found a potentially hoistable expression, now we look at every block BB dominates to see if it computes the expression. */ - for (j = 0; j < domby_len; j++) + for (j = 0; VEC_iterate (basic_block, domby, j, dominated); j++) { - dominated = domby[j]; /* Ignore self dominance. */ if (bb == dominated) continue; @@ -4878,8 +4926,8 @@ hoist_code (void) /* If we found nothing to hoist, then quit now. */ if (! found) { - free (domby); - continue; + VEC_free (basic_block, heap, domby); + continue; } /* Loop over all the hoistable expressions. */ @@ -4890,14 +4938,13 @@ hoist_code (void) insn_inserted_p = 0; /* These tests should be the same as the tests above. */ - if (TEST_BIT (hoist_vbeout[bb->index], i)) + if (TEST_BIT (hoist_exprs[bb->index], i)) { /* We've found a potentially hoistable expression, now we look at every block BB dominates to see if it computes the expression. */ - for (j = 0; j < domby_len; j++) + for (j = 0; VEC_iterate (basic_block, domby, j, dominated); j++) { - dominated = domby[j]; /* Ignore self dominance. */ if (bb == dominated) continue; @@ -4941,14 +4988,14 @@ hoist_code (void) occr->deleted_p = 1; if (!insn_inserted_p) { - insert_insn_end_bb (index_map[i], bb, 0); + insert_insn_end_basic_block (index_map[i], bb, 0); insn_inserted_p = 1; } } } } } - free (domby); + VEC_free (basic_block, heap, domby); } free (index_map); @@ -4965,8 +5012,8 @@ one_code_hoisting_pass (void) alloc_hash_table (max_cuid, &expr_hash_table, 0); compute_hash_table (&expr_hash_table); - if (gcse_file) - dump_hash_table (gcse_file, "Code Hosting Expressions", &expr_hash_table); + if (dump_file) + dump_hash_table (dump_file, "Code Hosting Expressions", &expr_hash_table); if (expr_hash_table.n_elems > 0) { @@ -5006,6 +5053,21 @@ one_code_hoisting_pass (void) load towards the exit, and we end up with no loads or stores of 'i' in the loop. */ +static hashval_t +pre_ldst_expr_hash (const void *p) +{ + int do_not_record_p = 0; + const struct ls_expr *x = 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; + return expr_equiv_p (ptr1->pattern, ptr2->pattern); +} + /* This will search the ldst list for a matching expression. If it doesn't find one, we create one and initialize it. */ @@ -5015,15 +5077,18 @@ ldst_entry (rtx x) int do_not_record_p = 0; struct ls_expr * ptr; unsigned int hash; + void **slot; + struct ls_expr e; hash = hash_rtx (x, GET_MODE (x), &do_not_record_p, NULL, /*have_reg_qty=*/false); - for (ptr = pre_ldst_mems; ptr != NULL; ptr = ptr->next) - if (ptr->hash_index == hash && expr_equiv_p (ptr->pattern, x)) - return ptr; + e.pattern = x; + slot = htab_find_slot_with_hash (pre_ldst_table, &e, hash, INSERT); + if (*slot) + return (struct ls_expr *)*slot; - ptr = xmalloc (sizeof (struct ls_expr)); + ptr = XNEW (struct ls_expr); ptr->next = pre_ldst_mems; ptr->expr = NULL; @@ -5036,6 +5101,7 @@ ldst_entry (rtx x) ptr->index = 0; ptr->hash_index = hash; pre_ldst_mems = ptr; + *slot = ptr; return ptr; } @@ -5056,6 +5122,10 @@ free_ldst_entry (struct ls_expr * ptr) static void free_ldst_mems (void) { + if (pre_ldst_table) + htab_delete (pre_ldst_table); + pre_ldst_table = NULL; + while (pre_ldst_mems) { struct ls_expr * tmp = pre_ldst_mems; @@ -5077,7 +5147,7 @@ print_ldst_list (FILE * file) fprintf (file, "LDST list: \n"); - for (ptr = first_ls_expr(); ptr != NULL; ptr = next_ls_expr (ptr)) + for (ptr = first_ls_expr (); ptr != NULL; ptr = next_ls_expr (ptr)) { fprintf (file, " Pattern (%3d): ", ptr->index); @@ -5108,13 +5178,15 @@ print_ldst_list (FILE * file) static struct ls_expr * find_rtx_in_ldst (rtx x) { - struct ls_expr * ptr; - - for (ptr = pre_ldst_mems; ptr != NULL; ptr = ptr->next) - if (expr_equiv_p (ptr->pattern, x) && ! ptr->invalid) - return ptr; - - return NULL; + struct ls_expr e; + void **slot; + if (!pre_ldst_table) + return NULL; + e.pattern = x; + slot = htab_find_slot (pre_ldst_table, &e, NO_INSERT); + if (!slot || ((struct ls_expr *)*slot)->invalid) + return NULL; + return *slot; } /* Assign each element of the list of mems a monotonically increasing value. */ @@ -5154,7 +5226,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; @@ -5235,6 +5307,8 @@ compute_ld_motion_mems (void) rtx insn; pre_ldst_mems = NULL; + pre_ldst_table = htab_create (13, pre_ldst_expr_hash, + pre_ldst_expr_eq, NULL); FOR_EACH_BB (bb) { @@ -5325,14 +5399,15 @@ trim_ld_motion_mems (void) else { *last = ptr->next; + htab_remove_elt_with_hash (pre_ldst_table, ptr, ptr->hash_index); free_ldst_entry (ptr); ptr = * last; } } /* Show the world what we've found. */ - if (gcse_file && pre_ldst_mems != NULL) - print_ldst_list (gcse_file); + if (dump_file && pre_ldst_mems != NULL) + print_ldst_list (dump_file); } /* This routine will take an expression which we are replacing with @@ -5371,19 +5446,20 @@ update_ld_motion_stores (struct expr * expr) if (expr->reaching_reg == src) continue; - if (gcse_file) + if (dump_file) { - fprintf (gcse_file, "PRE: store updated with reaching reg "); - print_rtl (gcse_file, expr->reaching_reg); - fprintf (gcse_file, ":\n "); - print_inline_rtx (gcse_file, insn, 8); - fprintf (gcse_file, "\n"); + fprintf (dump_file, "PRE: store updated with reaching reg "); + print_rtl (dump_file, expr->reaching_reg); + fprintf (dump_file, ":\n "); + print_inline_rtx (dump_file, insn, 8); + fprintf (dump_file, "\n"); } copy = gen_move_insn ( reg, copy_rtx (SET_SRC (pat))); new = emit_insn_before (copy, insn); record_one_set (REGNO (reg), new); SET_SRC (pat) = reg; + df_insn_rescan (insn); /* un-recognize this pattern since it's probably different now. */ INSN_CODE (insn) = -1; @@ -5415,7 +5491,7 @@ 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; @@ -5435,7 +5511,7 @@ 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; @@ -5452,9 +5528,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)) { @@ -5500,8 +5576,10 @@ extract_mentioned_regs_helper (rtx x, rtx accum) case PRE_DEC: case PRE_INC: + case PRE_MODIFY: case POST_DEC: case POST_INC: + case POST_MODIFY: /* We do not run this function with arguments having side effects. */ gcc_unreachable (); @@ -5510,6 +5588,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: @@ -5606,6 +5685,14 @@ find_moveable_store (rtx insn, int *regs_set_before, int *regs_set_after) if (find_reg_note (insn, REG_EH_REGION, NULL_RTX)) return; + /* Make sure that the SET_SRC of this store insns can be assigned to + a register, or we will fail later on in replace_store_insn, which + assumes that we can do this. But sometimes the target machine has + oddities like MEM read-modify-write instruction. See for example + PR24257. */ + if (!can_assign_to_reg_p (SET_SRC (set))) + return; + ptr = ldst_entry (dest); if (!ptr->pattern_regs) ptr->pattern_regs = extract_mentioned_regs (dest); @@ -5684,8 +5771,10 @@ compute_store_table (void) max_gcse_regno); sbitmap_vector_zero (reg_set_in_block, last_basic_block); pre_ldst_mems = 0; - last_set_in = xcalloc (max_gcse_regno, sizeof (int)); - already_set = xmalloc (sizeof (int) * max_gcse_regno); + pre_ldst_table = htab_create (13, pre_ldst_expr_hash, + pre_ldst_expr_eq, NULL); + last_set_in = XCNEWVEC (int, max_gcse_regno); + already_set = XNEWVEC (int, max_gcse_regno); /* Find all the stores we care about. */ FOR_EACH_BB (bb) @@ -5771,6 +5860,7 @@ compute_store_table (void) if (!AVAIL_STORE_LIST (ptr)) { *prev_next_ptr_ptr = ptr->next; + htab_remove_elt_with_hash (pre_ldst_table, ptr, ptr->hash_index); free_ldst_entry (ptr); } else @@ -5779,10 +5869,10 @@ compute_store_table (void) ret = enumerate_ldsts (); - if (gcse_file) + if (dump_file) { - fprintf (gcse_file, "ST_avail and ST_antic (shown under loads..)\n"); - print_ldst_list (gcse_file); + fprintf (dump_file, "ST_avail and ST_antic (shown under loads..)\n"); + print_ldst_list (dump_file); } free (last_set_in); @@ -5795,7 +5885,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); @@ -5810,7 +5900,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; @@ -5842,14 +5932,47 @@ find_loads (rtx x, rtx store_pattern, int after) return ret; } +static inline bool +store_killed_in_pat (const_rtx x, const_rtx pat, int after) +{ + if (GET_CODE (pat) == SET) + { + rtx dest = SET_DEST (pat); + + if (GET_CODE (dest) == ZERO_EXTRACT) + dest = XEXP (dest, 0); + + /* Check for memory stores to aliased objects. */ + if (MEM_P (dest) + && !expr_equiv_p (dest, x)) + { + if (after) + { + if (output_dependence (dest, x)) + return true; + } + else + { + if (output_dependence (x, dest)) + return true; + } + } + } + + if (find_loads (pat, x, after)) + return true; + + return false; +} + /* Check if INSN kills the store pattern X (is aliased with it). AFTER is true if we are checking the case when store X occurs 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; + const_rtx reg, base, note, pat; if (!INSN_P (insn)) return false; @@ -5876,32 +5999,20 @@ store_killed_in_insn (rtx x, rtx x_regs, rtx insn, int after) return false; } - if (GET_CODE (PATTERN (insn)) == SET) + pat = PATTERN (insn); + if (GET_CODE (pat) == SET) { - rtx pat = PATTERN (insn); - rtx dest = SET_DEST (pat); - - if (GET_CODE (dest) == ZERO_EXTRACT) - dest = XEXP (dest, 0); - - /* Check for memory stores to aliased objects. */ - if (MEM_P (dest) - && !expr_equiv_p (dest, x)) - { - if (after) - { - if (output_dependence (dest, x)) - return true; - } - else - { - if (output_dependence (x, dest)) - return true; - } - } - if (find_loads (SET_SRC (pat), x, after)) + if (store_killed_in_pat (x, pat, after)) return true; } + else if (GET_CODE (pat) == PARALLEL) + { + int i; + + for (i = 0; i < XVECLEN (pat, 0); i++) + if (store_killed_in_pat (x, XVECEXP (pat, 0, i), after)) + return true; + } else if (find_loads (PATTERN (insn), x, after)) return true; @@ -5927,7 +6038,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; @@ -5956,7 +6067,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); @@ -6004,8 +6115,8 @@ build_store_vectors (void) if (TEST_BIT (ae_gen[bb->index], ptr->index)) { rtx r = gen_reg_rtx (GET_MODE (ptr->pattern)); - if (gcse_file) - fprintf (gcse_file, "Removing redundant store:\n"); + if (dump_file) + fprintf (dump_file, "Removing redundant store:\n"); replace_store_insn (r, XEXP (st, 0), bb, ptr); continue; } @@ -6025,7 +6136,7 @@ build_store_vectors (void) transp = sbitmap_vector_alloc (last_basic_block, num_stores); sbitmap_vector_zero (transp, last_basic_block); - regs_set_in_block = xmalloc (sizeof (int) * max_gcse_regno); + regs_set_in_block = XNEWVEC (int, max_gcse_regno); FOR_EACH_BB (bb) { @@ -6050,12 +6161,12 @@ build_store_vectors (void) free (regs_set_in_block); - if (gcse_file) + if (dump_file) { - dump_sbitmap_vector (gcse_file, "st_antloc", "", st_antloc, last_basic_block); - dump_sbitmap_vector (gcse_file, "st_kill", "", ae_kill, last_basic_block); - dump_sbitmap_vector (gcse_file, "Transpt", "", transp, last_basic_block); - dump_sbitmap_vector (gcse_file, "st_avloc", "", ae_gen, last_basic_block); + dump_sbitmap_vector (dump_file, "st_antloc", "", st_antloc, last_basic_block); + dump_sbitmap_vector (dump_file, "st_kill", "", ae_kill, last_basic_block); + dump_sbitmap_vector (dump_file, "Transpt", "", transp, last_basic_block); + dump_sbitmap_vector (dump_file, "st_avloc", "", ae_gen, last_basic_block); } } @@ -6063,7 +6174,7 @@ build_store_vectors (void) the BB_HEAD if needed. */ static void -insert_insn_start_bb (rtx insn, basic_block bb) +insert_insn_start_basic_block (rtx insn, basic_block bb) { /* Insert at start of successor block. */ rtx prev = PREV_INSN (BB_HEAD (bb)); @@ -6071,8 +6182,7 @@ insert_insn_start_bb (rtx insn, basic_block bb) while (before != 0) { if (! LABEL_P (before) - && (! NOTE_P (before) - || NOTE_LINE_NUMBER (before) != NOTE_INSN_BASIC_BLOCK)) + && !NOTE_INSN_BASIC_BLOCK_P (before)) break; prev = before; if (prev == BB_END (bb)) @@ -6080,14 +6190,14 @@ insert_insn_start_bb (rtx insn, basic_block bb) before = NEXT_INSN (before); } - insn = emit_insn_after_noloc (insn, prev); + insn = emit_insn_after_noloc (insn, prev, bb); - if (gcse_file) + if (dump_file) { - fprintf (gcse_file, "STORE_MOTION insert store at start of BB %d:\n", + fprintf (dump_file, "STORE_MOTION insert store at start of BB %d:\n", bb->index); - print_inline_rtx (gcse_file, insn, 6); - fprintf (gcse_file, "\n"); + print_inline_rtx (dump_file, insn, 6); + fprintf (dump_file, "\n"); } } @@ -6137,7 +6247,7 @@ insert_store (struct ls_expr * expr, edge e) int index = EDGE_INDEX (edge_list, tmp->src, tmp->dest); RESET_BIT (pre_insert_map[index], expr->index); } - insert_insn_start_bb (insn, bb); + insert_insn_start_basic_block (insn, bb); return 0; } @@ -6147,12 +6257,12 @@ insert_store (struct ls_expr * expr, edge e) insert_insn_on_edge (insn, e); - if (gcse_file) + if (dump_file) { - fprintf (gcse_file, "STORE_MOTION insert insn on edge (%d, %d):\n", + fprintf (dump_file, "STORE_MOTION insert insn on edge (%d, %d):\n", e->src->index, e->dest->index); - print_inline_rtx (gcse_file, insn, 6); - fprintf (gcse_file, "\n"); + print_inline_rtx (dump_file, insn, 6); + fprintf (dump_file, "\n"); } return 1; @@ -6173,7 +6283,7 @@ remove_reachable_equiv_notes (basic_block bb, struct ls_expr *smexpr) rtx last, insn, note; rtx mem = smexpr->pattern; - stack = xmalloc (sizeof (edge_iterator) * n_basic_blocks); + stack = XNEWVEC (edge_iterator, n_basic_blocks); sp = 0; ei = ei_start (bb->succs); @@ -6222,8 +6332,8 @@ remove_reachable_equiv_notes (basic_block bb, struct ls_expr *smexpr) if (!note || !expr_equiv_p (XEXP (note, 0), mem)) continue; - if (gcse_file) - fprintf (gcse_file, "STORE_MOTION drop REG_EQUAL note at insn %d:\n", + if (dump_file) + fprintf (dump_file, "STORE_MOTION drop REG_EQUAL note at insn %d:\n", INSN_UID (insn)); remove_note (insn, note); } @@ -6251,17 +6361,6 @@ replace_store_insn (rtx reg, rtx del, basic_block bb, struct ls_expr *smexpr) mem = smexpr->pattern; insn = gen_move_insn (reg, SET_SRC (single_set (del))); - insn = emit_insn_after (insn, del); - - if (gcse_file) - { - fprintf (gcse_file, - "STORE_MOTION delete insn in BB %d:\n ", bb->index); - print_inline_rtx (gcse_file, del, 6); - fprintf (gcse_file, "\nSTORE MOTION replaced with insn:\n "); - print_inline_rtx (gcse_file, insn, 6); - fprintf (gcse_file, "\n"); - } for (ptr = ANTIC_STORE_LIST (smexpr); ptr; ptr = XEXP (ptr, 1)) if (XEXP (ptr, 0) == del) @@ -6289,6 +6388,20 @@ replace_store_insn (rtx reg, rtx del, basic_block bb, struct ls_expr *smexpr) XEXP (note, 0) = insn; } + /* 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) + { + 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); /* Now we must handle REG_EQUAL notes whose contents is equal to the mem; @@ -6306,8 +6419,8 @@ replace_store_insn (rtx reg, rtx del, basic_block bb, struct ls_expr *smexpr) if (!note || !expr_equiv_p (XEXP (note, 0), mem)) continue; - if (gcse_file) - fprintf (gcse_file, "STORE_MOTION drop REG_EQUAL note at insn %d:\n", + if (dump_file) + fprintf (dump_file, "STORE_MOTION drop REG_EQUAL note at insn %d:\n", INSN_UID (insn)); remove_note (insn, note); } @@ -6378,10 +6491,10 @@ store_motion (void) struct ls_expr * ptr; int update_flow = 0; - if (gcse_file) + if (dump_file) { - fprintf (gcse_file, "before store motion\n"); - print_rtl (gcse_file, get_insns ()); + fprintf (dump_file, "before store motion\n"); + print_rtl (dump_file, get_insns ()); } init_alias_analysis (); @@ -6390,6 +6503,8 @@ store_motion (void) num_stores = compute_store_table (); if (num_stores == 0) { + htab_delete (pre_ldst_table); + pre_ldst_table = NULL; sbitmap_vector_free (reg_set_in_block); end_alias_analysis (); return; @@ -6400,7 +6515,7 @@ store_motion (void) add_noreturn_fake_exit_edges (); connect_infinite_loops_to_exit (); - edge_list = pre_edge_rev_lcm (gcse_file, num_stores, transp, ae_gen, + edge_list = pre_edge_rev_lcm (num_stores, transp, ae_gen, st_antloc, ae_kill, &pre_insert_map, &pre_delete_map); @@ -6416,8 +6531,8 @@ store_motion (void) if (x >= 0) { - if (gcse_file != NULL) - fprintf (gcse_file, + if (dump_file != NULL) + fprintf (dump_file, "Can't replace store %d: abnormal edge from %d to %d\n", ptr->index, INDEX_EDGE (edge_list, x)->src->index, INDEX_EDGE (edge_list, x)->dest->index); @@ -6447,8 +6562,8 @@ store_motion (void) /* Entry point for jump bypassing optimization pass. */ -int -bypass_jumps (FILE *file) +static int +bypass_jumps (void) { int changed; @@ -6457,19 +6572,16 @@ bypass_jumps (FILE *file) if (current_function_calls_setjmp) return 0; - /* For calling dump_foo fns from gdb. */ - debug_stderr = stderr; - gcse_file = file; - /* Identify the basic block information for this function, including successors and predecessors. */ max_gcse_regno = max_reg_num (); - if (file) - dump_flow_info (file); + 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 <= 1 || is_too_expensive (_ ("jump bypassing disabled"))) + if (n_basic_blocks <= NUM_FIXED_BLOCKS + 1 + || is_too_expensive (_ ("jump bypassing disabled"))) return 0; gcc_obstack_init (&gcse_obstack); @@ -6495,11 +6607,11 @@ bypass_jumps (FILE *file) changed = one_cprop_pass (MAX_GCSE_PASSES + 2, true, true); free_gcse_mem (); - if (file) + if (dump_file) { - fprintf (file, "BYPASS of %s: %d basic blocks, ", + fprintf (dump_file, "BYPASS of %s: %d basic blocks, ", current_function_name (), n_basic_blocks); - fprintf (file, "%d bytes\n\n", bytes_used); + fprintf (dump_file, "%d bytes\n\n", bytes_used); } obstack_free (&gcse_obstack, NULL); @@ -6507,7 +6619,6 @@ bypass_jumps (FILE *file) /* We are finished with alias. */ end_alias_analysis (); - allocate_reg_info (max_reg_num (), FALSE, FALSE); return changed; } @@ -6529,9 +6640,9 @@ is_too_expensive (const char *pass) graceful degradation. */ if (n_edges > 20000 + n_basic_blocks * 4) { - if (warn_disabled_optimization) - warning (0, "%s: %d basic blocks and %d edges/basic block", - pass, n_basic_blocks, n_edges / n_basic_blocks); + warning (OPT_Wdisabled_optimization, + "%s: %d basic blocks and %d edges/basic block", + pass, n_basic_blocks, n_edges / n_basic_blocks); return true; } @@ -6542,14 +6653,122 @@ is_too_expensive (const char *pass) * SBITMAP_SET_SIZE (max_reg_num ()) * sizeof (SBITMAP_ELT_TYPE)) > MAX_GCSE_MEMORY) { - if (warn_disabled_optimization) - warning (0, "%s: %d basic blocks and %d registers", - pass, n_basic_blocks, max_reg_num ()); + warning (OPT_Wdisabled_optimization, + "%s: %d basic blocks and %d registers", + pass, n_basic_blocks, max_reg_num ()); return true; } return false; } + +static bool +gate_handle_jump_bypass (void) +{ + return optimize > 0 && flag_gcse; +} + +/* Perform jump bypassing and control flow optimizations. */ +static unsigned int +rest_of_handle_jump_bypass (void) +{ + delete_unreachable_blocks (); + if (bypass_jumps ()) + { + delete_trivially_dead_insns (get_insns (), max_reg_num ()); + rebuild_jump_labels (get_insns ()); + cleanup_cfg (0); + } + return 0; +} + +struct tree_opt_pass pass_jump_bypass = +{ + "bypass", /* name */ + gate_handle_jump_bypass, /* gate */ + rest_of_handle_jump_bypass, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_BYPASS, /* tv_id */ + 0, /* 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 */ +}; + + +static bool +gate_handle_gcse (void) +{ + return optimize > 0 && flag_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; +} + +struct tree_opt_pass pass_gcse = +{ + "gcse1", /* name */ + gate_handle_gcse, /* gate */ + rest_of_handle_gcse, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_GCSE, /* 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_verify_flow | TODO_ggc_collect, /* todo_flags_finish */ + 'G' /* letter */ +}; + #include "gt-gcse.h"