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. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
/* TODO
- reordering of memory allocation and freeing to be more space efficient
#include "intl.h"
#include "obstack.h"
#include "timevar.h"
+#include "tree-pass.h"
+#include "hashtab.h"
/* Propagate flow information through back edges and thus enable PRE's
moving loop invariant calculations out of loops.
\f
/* 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.
* 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;
/* 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. */
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. */
/* 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);
+ 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);
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. */
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);
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);
}
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:
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. */
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
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)
+ /* 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)
XEXP (note, 0) = simplify_replace_rtx (XEXP (note, 0), from, to);
if (!success && set && reg_mentioned_p (from, SET_SRC (set)))
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));
}
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;
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);
{
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;
{
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
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;
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;
/* 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;
}
}
}
- if (gcse_file != NULL)
- fprintf (gcse_file, "\n");
+ if (dump_file != NULL)
+ fprintf (dump_file, "\n");
return changed;
}
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.
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);
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);
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, ",
+ 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. */
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;
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;
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);
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);
}
}
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);
}
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;
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:
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);
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));
}
}
/* 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;
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)
{
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);
}
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 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. */
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. */
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
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)
/* 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;
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
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)
{
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. */
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;
ptr->index = 0;
ptr->hash_index = hash;
pre_ldst_mems = ptr;
+ *slot = ptr;
return 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;
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. */
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)
{
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
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)));
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);
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)
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
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);
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;
}
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)
{
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);
}
}
insn = emit_insn_after_noloc (insn, prev);
- 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");
}
}
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;
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);
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);
}
insn = gen_move_insn (reg, SET_SRC (single_set (del)));
insn = emit_insn_after (insn, del);
- if (gcse_file)
+ if (dump_file)
{
- fprintf (gcse_file,
+ fprintf (dump_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");
+ 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 (!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);
}
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 ();
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;
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);
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);
\f
/* Entry point for jump bypassing optimization pass. */
-int
-bypass_jumps (FILE *file)
+static int
+bypass_jumps (void)
{
int changed;
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);
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);
return false;
}
+\f
+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)
+{
+ cleanup_cfg (CLEANUP_EXPENSIVE);
+ reg_scan (get_insns (), max_reg_num ());
+
+ if (bypass_jumps ())
+ {
+ rebuild_jump_labels (get_insns ());
+ cleanup_cfg (CLEANUP_EXPENSIVE);
+ delete_trivially_dead_insns (get_insns (), max_reg_num ());
+ }
+ 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 ());
+ rebuild_jump_labels (get_insns ());
+ delete_trivially_dead_insns (get_insns (), max_reg_num ());
+
+ 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);
+ reg_scan (get_insns (), max_reg_num ());
+ tem2 = cse_main (get_insns (), max_reg_num ());
+ 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)
+ {
+ timevar_push (TV_JUMP);
+ rebuild_jump_labels (get_insns ());
+ delete_dead_jumptables ();
+ cleanup_cfg (CLEANUP_EXPENSIVE);
+ timevar_pop (TV_JUMP);
+ }
+
+ 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_dump_func |
+ TODO_verify_flow | TODO_ggc_collect, /* todo_flags_finish */
+ 'G' /* letter */
+};
+
#include "gt-gcse.h"