Commit 43c8a043 by Eric Botcazou Committed by Eric Botcazou

gcse.c: Adjust outdated comments throughout.

	* gcse.c: Adjust outdated comments throughout.
	(struct mem_conflict_info): New structure.
	(mems_conflict_for_gcse_p): Use it to communicate with caller.
	(load_killed_in_block_p): Pass it to note_stores.
	(hash_expr): Remove superfluous line break.
	(hash_scan_set): Rename PAT parameter into SET.
	(hash_scan_insn): Reorder cases.
	(canon_list_insert): Fix long line.
	(edge_list): Delete.
	(prune_expressions): Rename E local variable into EXPR.
	(compute_pre_data): Return struct edge_list * object.
	(pre_expr_reaches_here_p_work): Fix formatting.
	(process_insert_insn): Move around comment.
	(pre_edge_insert): Fix long line.
	(pre_insert_copies): Likewise.
	(gcse_emit_move_after): Swap SRC and DEST parameters.
	(pre_delete): Adjust call to gcse_emit_move_after.
	(pre_gcse): Take struct edge_list * parameter.  Fix long line.
	(one_pre_gcse_pass): Use flag_gcse_lm condition for all routines.
	Use a local list of edges.
	(hoist_code): Fix long line.  Adjust call to gcse_emit_move_after.
	(pre_ldst_expr_hash): Fix long line.
	(free_ldst_mems): Rename into...
	(free_ld_motion_mems): ...this.
	(first_ls_expr): Delete.
	(next_ls_expr): Likewise.
	(print_ldst_list): Do not use above two functions.
	(simple_mem): Adjust interface.
	(compute_ld_motion_mems): Fix formatting.
	(update_ld_motion_stores): Reuse local variable.

From-SVN: r181054
parent c8772697
2011-11-06 Eric Botcazou <ebotcazou@adacore.com>
* gcse.c: Adjust outdated comments throughout.
(struct mem_conflict_info): New structure.
(mems_conflict_for_gcse_p): Use it to communicate with caller.
(load_killed_in_block_p): Pass it to note_stores.
(hash_expr): Remove superfluous line break.
(hash_scan_set): Rename PAT parameter into SET.
(hash_scan_insn): Reorder cases.
(canon_list_insert): Fix long line.
(edge_list): Delete.
(prune_expressions): Rename E local variable into EXPR.
(compute_pre_data): Return struct edge_list * object.
(pre_expr_reaches_here_p_work): Fix formatting.
(process_insert_insn): Move around comment.
(pre_edge_insert): Fix long line.
(pre_insert_copies): Likewise.
(gcse_emit_move_after): Swap SRC and DEST parameters.
(pre_delete): Adjust call to gcse_emit_move_after.
(pre_gcse): Take struct edge_list * parameter. Fix long line.
(one_pre_gcse_pass): Use flag_gcse_lm condition for all routines.
Use a local list of edges.
(hoist_code): Fix long line. Adjust call to gcse_emit_move_after.
(pre_ldst_expr_hash): Fix long line.
(free_ldst_mems): Rename into...
(free_ld_motion_mems): ...this.
(first_ls_expr): Delete.
(next_ls_expr): Likewise.
(print_ldst_list): Do not use above two functions.
(simple_mem): Adjust interface.
(compute_ld_motion_mems): Fix formatting.
(update_ld_motion_stores): Reuse local variable.
2011-11-06 Joseph Myers <joseph@codesourcery.com> 2011-11-06 Joseph Myers <joseph@codesourcery.com>
* c-decl.c (shadow_tag_warned, grokdeclarator): Handle _Alignas * c-decl.c (shadow_tag_warned, grokdeclarator): Handle _Alignas
...@@ -23,10 +23,6 @@ along with GCC; see the file COPYING3. If not see ...@@ -23,10 +23,6 @@ along with GCC; see the file COPYING3. If not see
- do rough calc of how many regs are needed in each block, and a rough - do rough calc of how many regs are needed in each block, and a rough
calc of how many regs are available in each class and use that to calc of how many regs are available in each class and use that to
throttle back the code in cases where RTX_COST is minimal. throttle back the code in cases where RTX_COST is minimal.
- a store to the same address as a load does not kill the load if the
source of the store is also the destination of the load. Handling this
allows more load motion, particularly out of loops.
*/ */
/* References searched while implementing this. /* References searched while implementing this.
...@@ -267,7 +263,7 @@ struct reg_use {rtx reg_rtx; }; ...@@ -267,7 +263,7 @@ struct reg_use {rtx reg_rtx; };
struct expr struct expr
{ {
/* The expression (SET_SRC for expressions, PATTERN for assignments). */ /* The expression. */
rtx expr; rtx expr;
/* Index in the available expression bitmaps. */ /* Index in the available expression bitmaps. */
int bitmap_index; int bitmap_index;
...@@ -346,14 +342,12 @@ static struct hash_table_d expr_hash_table; ...@@ -346,14 +342,12 @@ static struct hash_table_d expr_hash_table;
/* This is a list of expressions which are MEMs and will be used by load /* This is a list of expressions which are MEMs and will be used by load
or store motion. or store motion.
Load motion tracks MEMs which aren't killed by Load motion tracks MEMs which aren't killed by anything except itself,
anything except itself. (i.e., loads and stores to a single location). i.e. loads and stores to a single location.
We can then allow movement of these MEM refs with a little special We can then allow movement of these MEM refs with a little special
allowance. (all stores copy the same value to the reaching reg used allowance. (all stores copy the same value to the reaching reg used
for the loads). This means all values used to store into memory must have for the loads). This means all values used to store into memory must have
no side effects so we can re-issue the setter value. no side effects so we can re-issue the setter value. */
Store Motion uses this structure as an expression table to track stores
which look interesting, and might be moveable towards the exit block. */
struct ls_expr struct ls_expr
{ {
...@@ -454,14 +448,14 @@ static int load_killed_in_block_p (const_basic_block, int, const_rtx, int); ...@@ -454,14 +448,14 @@ static int load_killed_in_block_p (const_basic_block, int, const_rtx, int);
static void canon_list_insert (rtx, const_rtx, void *); static void canon_list_insert (rtx, const_rtx, void *);
static void alloc_pre_mem (int, int); static void alloc_pre_mem (int, int);
static void free_pre_mem (void); static void free_pre_mem (void);
static void compute_pre_data (void); static struct edge_list *compute_pre_data (void);
static int pre_expr_reaches_here_p (basic_block, struct expr *, static int pre_expr_reaches_here_p (basic_block, struct expr *,
basic_block); basic_block);
static void insert_insn_end_basic_block (struct expr *, basic_block); static void insert_insn_end_basic_block (struct expr *, basic_block);
static void pre_insert_copy_insn (struct expr *, rtx); static void pre_insert_copy_insn (struct expr *, rtx);
static void pre_insert_copies (void); static void pre_insert_copies (void);
static int pre_delete (void); static int pre_delete (void);
static int pre_gcse (void); static int pre_gcse (struct edge_list *);
static int one_pre_gcse_pass (void); static int one_pre_gcse_pass (void);
static void add_label_notes (rtx, rtx); static void add_label_notes (rtx, rtx);
static void alloc_code_hoist_mem (int, int); static void alloc_code_hoist_mem (int, int);
...@@ -478,11 +472,9 @@ static int pre_expr_reaches_here_p_work (basic_block, struct expr *, ...@@ -478,11 +472,9 @@ static int pre_expr_reaches_here_p_work (basic_block, struct expr *,
basic_block, char *); basic_block, char *);
static struct ls_expr * ldst_entry (rtx); static struct ls_expr * ldst_entry (rtx);
static void free_ldst_entry (struct ls_expr *); static void free_ldst_entry (struct ls_expr *);
static void free_ldst_mems (void); static void free_ld_motion_mems (void);
static void print_ldst_list (FILE *); static void print_ldst_list (FILE *);
static struct ls_expr * find_rtx_in_ldst (rtx); static struct ls_expr * find_rtx_in_ldst (rtx);
static inline struct ls_expr * first_ls_expr (void);
static inline struct ls_expr * next_ls_expr (struct ls_expr *);
static int simple_mem (const_rtx); static int simple_mem (const_rtx);
static void invalidate_any_buried_refs (rtx); static void invalidate_any_buried_refs (rtx);
static void compute_ld_motion_mems (void); static void compute_ld_motion_mems (void);
...@@ -556,7 +548,6 @@ can_copy_p (enum machine_mode mode) ...@@ -556,7 +548,6 @@ can_copy_p (enum machine_mode mode)
return can_copy[mode] != 0; return can_copy[mode] != 0;
} }
/* Cover function to xmalloc to record bytes allocated. */ /* Cover function to xmalloc to record bytes allocated. */
static void * static void *
...@@ -714,7 +705,6 @@ struct reg_avail_info ...@@ -714,7 +705,6 @@ struct reg_avail_info
static struct reg_avail_info *reg_avail_info; static struct reg_avail_info *reg_avail_info;
static basic_block current_bb; static basic_block current_bb;
/* See whether X, the source of a set, is something we want to consider for /* See whether X, the source of a set, is something we want to consider for
GCSE. */ GCSE. */
...@@ -935,25 +925,29 @@ oprs_unchanged_p (const_rtx x, const_rtx insn, int avail_p) ...@@ -935,25 +925,29 @@ oprs_unchanged_p (const_rtx x, const_rtx insn, int avail_p)
return 1; return 1;
} }
/* Used for communication between mems_conflict_for_gcse_p and /* Info passed from load_killed_in_block_p to mems_conflict_for_gcse_p. */
load_killed_in_block_p. Nonzero if mems_conflict_for_gcse_p finds a
conflict between two memory references. */
static int gcse_mems_conflict_p;
/* Used for communication between mems_conflict_for_gcse_p and struct mem_conflict_info
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 /* A memory reference for a load instruction, mems_conflict_for_gcse_p will
this memory load. */ see if a memory store conflicts with this memory load. */
static const_rtx gcse_mem_operand; const_rtx mem;
/* DEST is the output of an instruction. If it is a memory reference, and /* True if mems_conflict_for_gcse_p finds a conflict between two memory
possibly conflicts with the load found in gcse_mem_operand, then set references. */
gcse_mems_conflict_p to a nonzero value. */ bool conflict;
};
/* DEST is the output of an instruction. If it is a memory reference and
possibly conflicts with the load found in DATA, then communicate this
information back through DATA. */
static void static void
mems_conflict_for_gcse_p (rtx dest, const_rtx setter ATTRIBUTE_UNUSED, mems_conflict_for_gcse_p (rtx dest, const_rtx setter ATTRIBUTE_UNUSED,
void *data ATTRIBUTE_UNUSED) void *data)
{ {
struct mem_conflict_info *mci = (struct mem_conflict_info *) data;
while (GET_CODE (dest) == SUBREG while (GET_CODE (dest) == SUBREG
|| GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == ZERO_EXTRACT
|| GET_CODE (dest) == STRICT_LOW_PART) || GET_CODE (dest) == STRICT_LOW_PART)
...@@ -967,17 +961,15 @@ mems_conflict_for_gcse_p (rtx dest, const_rtx setter ATTRIBUTE_UNUSED, ...@@ -967,17 +961,15 @@ mems_conflict_for_gcse_p (rtx dest, const_rtx setter ATTRIBUTE_UNUSED,
/* If we are setting a MEM in our list of specially recognized MEMs, /* If we are setting a MEM in our list of specially recognized MEMs,
don't mark as killed this time. */ don't mark as killed this time. */
if (pre_ldst_mems != NULL && expr_equiv_p (dest, mci->mem))
if (expr_equiv_p (dest, gcse_mem_operand) && pre_ldst_mems != NULL)
{ {
if (!find_rtx_in_ldst (dest)) if (!find_rtx_in_ldst (dest))
gcse_mems_conflict_p = 1; mci->conflict = true;
return; return;
} }
if (true_dependence (dest, GET_MODE (dest), gcse_mem_operand, if (true_dependence (dest, GET_MODE (dest), mci->mem, rtx_addr_varies_p))
rtx_addr_varies_p)) mci->conflict = true;
gcse_mems_conflict_p = 1;
} }
/* Return nonzero if the expression in X (a memory reference) is killed /* Return nonzero if the expression in X (a memory reference) is killed
...@@ -989,7 +981,8 @@ mems_conflict_for_gcse_p (rtx dest, const_rtx setter ATTRIBUTE_UNUSED, ...@@ -989,7 +981,8 @@ mems_conflict_for_gcse_p (rtx dest, const_rtx setter ATTRIBUTE_UNUSED,
AVAIL_P to 0. */ AVAIL_P to 0. */
static int static int
load_killed_in_block_p (const_basic_block bb, int uid_limit, const_rtx x, int avail_p) load_killed_in_block_p (const_basic_block bb, int uid_limit, const_rtx x,
int avail_p)
{ {
VEC (rtx,heap) *list = modify_mem_list[bb->index]; VEC (rtx,heap) *list = modify_mem_list[bb->index];
rtx setter; rtx setter;
...@@ -1001,6 +994,8 @@ load_killed_in_block_p (const_basic_block bb, int uid_limit, const_rtx x, int av ...@@ -1001,6 +994,8 @@ load_killed_in_block_p (const_basic_block bb, int uid_limit, const_rtx x, int av
FOR_EACH_VEC_ELT_REVERSE (rtx, list, ix, setter) FOR_EACH_VEC_ELT_REVERSE (rtx, list, ix, setter)
{ {
struct mem_conflict_info mci;
/* Ignore entries in the list that do not apply. */ /* Ignore entries in the list that do not apply. */
if ((avail_p if ((avail_p
&& DF_INSN_LUID (setter) < uid_limit) && DF_INSN_LUID (setter) < uid_limit)
...@@ -1015,14 +1010,11 @@ load_killed_in_block_p (const_basic_block bb, int uid_limit, const_rtx x, int av ...@@ -1015,14 +1010,11 @@ load_killed_in_block_p (const_basic_block bb, int uid_limit, const_rtx x, int av
return 1; return 1;
/* SETTER must be an INSN of some kind that sets memory. Call /* SETTER must be an INSN of some kind that sets memory. Call
note_stores to examine each hunk of memory that is modified. note_stores to examine each hunk of memory that is modified. */
mci.mem = x;
The note_stores interface is pretty limited, so we have to mci.conflict = false;
communicate via global variables. Yuk. */ note_stores (PATTERN (setter), mems_conflict_for_gcse_p, &mci);
gcse_mem_operand = x; if (mci.conflict)
gcse_mems_conflict_p = 0;
note_stores (PATTERN (setter), mems_conflict_for_gcse_p, NULL);
if (gcse_mems_conflict_p)
return 1; return 1;
} }
return 0; return 0;
...@@ -1061,8 +1053,7 @@ hash_expr (const_rtx x, enum machine_mode mode, int *do_not_record_p, ...@@ -1061,8 +1053,7 @@ hash_expr (const_rtx x, enum machine_mode mode, int *do_not_record_p,
*do_not_record_p = 0; *do_not_record_p = 0;
hash = hash_rtx (x, mode, do_not_record_p, hash = hash_rtx (x, mode, do_not_record_p, NULL, /*have_reg_qty=*/false);
NULL, /*have_reg_qty=*/false);
return hash % hash_table_size; return hash % hash_table_size;
} }
...@@ -1190,13 +1181,13 @@ insert_expr_in_table (rtx x, enum machine_mode mode, rtx insn, int antic_p, ...@@ -1190,13 +1181,13 @@ insert_expr_in_table (rtx x, enum machine_mode mode, rtx insn, int antic_p,
} }
} }
/* Scan pattern PAT of INSN and add an entry to the hash TABLE. */ /* Scan SET present in INSN and add an entry to the hash TABLE. */
static void static void
hash_scan_set (rtx pat, rtx insn, struct hash_table_d *table) hash_scan_set (rtx set, rtx insn, struct hash_table_d *table)
{ {
rtx src = SET_SRC (pat); rtx src = SET_SRC (set);
rtx dest = SET_DEST (pat); rtx dest = SET_DEST (set);
rtx note; rtx note;
if (GET_CODE (src) == CALL) if (GET_CODE (src) == CALL)
...@@ -1227,7 +1218,7 @@ hash_scan_set (rtx pat, rtx insn, struct hash_table_d *table) ...@@ -1227,7 +1218,7 @@ hash_scan_set (rtx pat, rtx insn, struct hash_table_d *table)
&& REG_NOTE_KIND (note) == REG_EQUAL && REG_NOTE_KIND (note) == REG_EQUAL
&& !REG_P (src) && !REG_P (src)
&& want_to_gcse_p (XEXP (note, 0), NULL)) && want_to_gcse_p (XEXP (note, 0), NULL))
src = XEXP (note, 0), pat = gen_rtx_SET (VOIDmode, dest, src); src = XEXP (note, 0), set = gen_rtx_SET (VOIDmode, dest, src);
/* Only record sets of pseudo-regs in the hash table. */ /* Only record sets of pseudo-regs in the hash table. */
if (regno >= FIRST_PSEUDO_REGISTER if (regno >= FIRST_PSEUDO_REGISTER
...@@ -1242,7 +1233,7 @@ hash_scan_set (rtx pat, rtx insn, struct hash_table_d *table) ...@@ -1242,7 +1233,7 @@ hash_scan_set (rtx pat, rtx insn, struct hash_table_d *table)
/* Is SET_SRC something we want to gcse? */ /* Is SET_SRC something we want to gcse? */
&& want_to_gcse_p (src, &max_distance) && want_to_gcse_p (src, &max_distance)
/* Don't CSE a nop. */ /* Don't CSE a nop. */
&& ! set_noop_p (pat) && ! set_noop_p (set)
/* Don't GCSE if it has attached REG_EQUIV note. /* Don't GCSE if it has attached REG_EQUIV note.
At this point this only function parameters should have At this point this only function parameters should have
REG_EQUIV notes and if the argument slot is used somewhere REG_EQUIV notes and if the argument slot is used somewhere
...@@ -1286,7 +1277,7 @@ hash_scan_set (rtx pat, rtx insn, struct hash_table_d *table) ...@@ -1286,7 +1277,7 @@ hash_scan_set (rtx pat, rtx insn, struct hash_table_d *table)
/* Is SET_DEST something we want to gcse? */ /* Is SET_DEST something we want to gcse? */
&& want_to_gcse_p (dest, &max_distance) && want_to_gcse_p (dest, &max_distance)
/* Don't CSE a nop. */ /* Don't CSE a nop. */
&& ! set_noop_p (pat) && ! set_noop_p (set)
/* Don't GCSE if it has attached REG_EQUIV note. /* Don't GCSE if it has attached REG_EQUIV note.
At this point this only function parameters should have At this point this only function parameters should have
REG_EQUIV notes and if the argument slot is used somewhere REG_EQUIV notes and if the argument slot is used somewhere
...@@ -1325,16 +1316,7 @@ hash_scan_call (rtx x ATTRIBUTE_UNUSED, rtx insn ATTRIBUTE_UNUSED, ...@@ -1325,16 +1316,7 @@ hash_scan_call (rtx x ATTRIBUTE_UNUSED, rtx insn ATTRIBUTE_UNUSED,
/* Currently nothing to do. */ /* Currently nothing to do. */
} }
/* Process INSN and add hash table entries as appropriate. /* Process INSN and add hash table entries as appropriate. */
Only available expressions that set a single pseudo-reg are recorded.
Single sets in a PARALLEL could be handled, but it's an extra complication
that isn't dealt with right now. The trick is handling the CLOBBERs that
are also in the PARALLEL. Later.
If SET_P is nonzero, this is for the assignment hash table,
otherwise it is for the expression hash table. */
static void static void
hash_scan_insn (rtx insn, struct hash_table_d *table) hash_scan_insn (rtx insn, struct hash_table_d *table)
...@@ -1347,6 +1329,13 @@ hash_scan_insn (rtx insn, struct hash_table_d *table) ...@@ -1347,6 +1329,13 @@ hash_scan_insn (rtx insn, struct hash_table_d *table)
if (GET_CODE (pat) == SET) if (GET_CODE (pat) == SET)
hash_scan_set (pat, insn, table); hash_scan_set (pat, insn, table);
else if (GET_CODE (pat) == CLOBBER)
hash_scan_clobber (pat, insn, table);
else if (GET_CODE (pat) == CALL)
hash_scan_call (pat, insn, table);
else if (GET_CODE (pat) == PARALLEL) else if (GET_CODE (pat) == PARALLEL)
for (i = 0; i < XVECLEN (pat, 0); i++) for (i = 0; i < XVECLEN (pat, 0); i++)
{ {
...@@ -1359,13 +1348,10 @@ hash_scan_insn (rtx insn, struct hash_table_d *table) ...@@ -1359,13 +1348,10 @@ hash_scan_insn (rtx insn, struct hash_table_d *table)
else if (GET_CODE (x) == CALL) else if (GET_CODE (x) == CALL)
hash_scan_call (x, insn, table); hash_scan_call (x, insn, table);
} }
else if (GET_CODE (pat) == CLOBBER)
hash_scan_clobber (pat, insn, table);
else if (GET_CODE (pat) == CALL)
hash_scan_call (pat, insn, table);
} }
/* Dump the hash table TABLE to file FILE under the name NAME. */
static void static void
dump_hash_table (FILE *file, const char *name, struct hash_table_d *table) dump_hash_table (FILE *file, const char *name, struct hash_table_d *table)
{ {
...@@ -1429,13 +1415,12 @@ record_last_reg_set_info (rtx insn, int regno) ...@@ -1429,13 +1415,12 @@ record_last_reg_set_info (rtx insn, int regno)
} }
} }
/* Record all of the canonicalized MEMs of record_last_mem_set_info's insn. /* Record all of the canonicalized MEMs of record_last_mem_set_info's insn.
Note we store a pair of elements in the list, so they have to be Note we store a pair of elements in the list, so they have to be
taken off pairwise. */ taken off pairwise. */
static void static void
canon_list_insert (rtx dest ATTRIBUTE_UNUSED, const_rtx unused1 ATTRIBUTE_UNUSED, canon_list_insert (rtx dest ATTRIBUTE_UNUSED, const_rtx x ATTRIBUTE_UNUSED,
void * v_insn) void * v_insn)
{ {
rtx dest_addr, insn; rtx dest_addr, insn;
...@@ -1635,7 +1620,6 @@ free_modify_mem_tables (void) ...@@ -1635,7 +1620,6 @@ free_modify_mem_tables (void)
canon_modify_mem_list = 0; canon_modify_mem_list = 0;
} }
/* For each block, compute whether X is transparent. X is either an /* For each block, compute whether X is transparent. X is either an
expression or an assignment [though we don't care which, for this context expression or an assignment [though we don't care which, for this context
an assignment is treated as an expression]. For each block where an an assignment is treated as an expression]. For each block where an
...@@ -1746,10 +1730,10 @@ compute_transp (const_rtx x, int indx, sbitmap *bmap) ...@@ -1746,10 +1730,10 @@ compute_transp (const_rtx x, int indx, sbitmap *bmap)
} }
} }
/* Compute PRE+LCM working variables. */ /* Compute PRE+LCM working variables. */
/* Local properties of expressions. */ /* Local properties of expressions. */
/* Nonzero for expressions that are transparent in the block. */ /* Nonzero for expressions that are transparent in the block. */
static sbitmap *transp; static sbitmap *transp;
...@@ -1772,9 +1756,6 @@ static sbitmap *pre_insert_map; ...@@ -1772,9 +1756,6 @@ static sbitmap *pre_insert_map;
/* Nonzero for expressions which should be deleted in a specific block. */ /* Nonzero for expressions which should be deleted in a specific block. */
static sbitmap *pre_delete_map; static sbitmap *pre_delete_map;
/* Contains the edge_list returned by pre_edge_lcm. */
static struct edge_list *edge_list;
/* Allocate vars used for PRE analysis. */ /* Allocate vars used for PRE analysis. */
static void static void
...@@ -1826,6 +1807,7 @@ static void ...@@ -1826,6 +1807,7 @@ static void
prune_expressions (bool pre_p) prune_expressions (bool pre_p)
{ {
sbitmap prune_exprs; sbitmap prune_exprs;
struct expr *expr;
unsigned int ui; unsigned int ui;
basic_block bb; basic_block bb;
...@@ -1833,17 +1815,16 @@ prune_expressions (bool pre_p) ...@@ -1833,17 +1815,16 @@ prune_expressions (bool pre_p)
sbitmap_zero (prune_exprs); sbitmap_zero (prune_exprs);
for (ui = 0; ui < expr_hash_table.size; ui++) for (ui = 0; ui < expr_hash_table.size; ui++)
{ {
struct expr *e; for (expr = expr_hash_table.table[ui]; expr; expr = expr->next_same_hash)
for (e = expr_hash_table.table[ui]; e != NULL; e = e->next_same_hash)
{ {
/* Note potentially trapping expressions. */ /* Note potentially trapping expressions. */
if (may_trap_p (e->expr)) if (may_trap_p (expr->expr))
{ {
SET_BIT (prune_exprs, e->bitmap_index); SET_BIT (prune_exprs, expr->bitmap_index);
continue; continue;
} }
if (!pre_p && MEM_P (e->expr)) if (!pre_p && MEM_P (expr->expr))
/* Note memory references that can be clobbered by a call. /* Note memory references that can be clobbered by a call.
We do not split abnormal edges in hoisting, so would We do not split abnormal edges in hoisting, so would
a memory reference get hoisted along an abnormal edge, a memory reference get hoisted along an abnormal edge,
...@@ -1851,13 +1832,13 @@ prune_expressions (bool pre_p) ...@@ -1851,13 +1832,13 @@ prune_expressions (bool pre_p)
constant memory references can be hoisted along abnormal constant memory references can be hoisted along abnormal
edges. */ edges. */
{ {
if (GET_CODE (XEXP (e->expr, 0)) == SYMBOL_REF if (GET_CODE (XEXP (expr->expr, 0)) == SYMBOL_REF
&& CONSTANT_POOL_ADDRESS_P (XEXP (e->expr, 0))) && CONSTANT_POOL_ADDRESS_P (XEXP (expr->expr, 0)))
continue; continue;
if (MEM_READONLY_P (e->expr) if (MEM_READONLY_P (expr->expr)
&& !MEM_VOLATILE_P (e->expr) && !MEM_VOLATILE_P (expr->expr)
&& MEM_NOTRAP_P (e->expr)) && MEM_NOTRAP_P (expr->expr))
/* Constant memory reference, e.g., a PIC address. */ /* Constant memory reference, e.g., a PIC address. */
continue; continue;
...@@ -1865,7 +1846,7 @@ prune_expressions (bool pre_p) ...@@ -1865,7 +1846,7 @@ prune_expressions (bool pre_p)
analysis to determine if this mem is actually killed analysis to determine if this mem is actually killed
by this call. */ by this call. */
SET_BIT (prune_exprs, e->bitmap_index); SET_BIT (prune_exprs, expr->bitmap_index);
} }
} }
} }
...@@ -1976,9 +1957,10 @@ prune_insertions_deletions (int n_elems) ...@@ -1976,9 +1957,10 @@ prune_insertions_deletions (int n_elems)
/* Top level routine to do the dataflow analysis needed by PRE. */ /* Top level routine to do the dataflow analysis needed by PRE. */
static void static struct edge_list *
compute_pre_data (void) compute_pre_data (void)
{ {
struct edge_list *edge_list;
basic_block bb; basic_block bb;
compute_local_properties (transp, comp, antloc, &expr_hash_table); compute_local_properties (transp, comp, antloc, &expr_hash_table);
...@@ -2004,6 +1986,8 @@ compute_pre_data (void) ...@@ -2004,6 +1986,8 @@ compute_pre_data (void)
ae_kill = NULL; ae_kill = NULL;
prune_insertions_deletions (expr_hash_table.n_elems); prune_insertions_deletions (expr_hash_table.n_elems);
return edge_list;
} }
/* PRE utilities */ /* PRE utilities */
...@@ -2022,7 +2006,8 @@ compute_pre_data (void) ...@@ -2022,7 +2006,8 @@ compute_pre_data (void)
the closest such expression. */ the closest such expression. */
static int static int
pre_expr_reaches_here_p_work (basic_block occr_bb, struct expr *expr, basic_block bb, char *visited) pre_expr_reaches_here_p_work (basic_block occr_bb, struct expr *expr,
basic_block bb, char *visited)
{ {
edge pred; edge pred;
edge_iterator ei; edge_iterator ei;
...@@ -2079,15 +2064,13 @@ pre_expr_reaches_here_p (basic_block occr_bb, struct expr *expr, basic_block bb) ...@@ -2079,15 +2064,13 @@ pre_expr_reaches_here_p (basic_block occr_bb, struct expr *expr, basic_block bb)
return rval; return rval;
} }
/* Generate RTL to copy an EXPR to its `reaching_reg' and return it. */
/* Given an expr, generate RTL which we can insert at the end of a BB,
or on an edge. Set the block number of any insns generated to
the value of BB. */
static rtx static rtx
process_insert_insn (struct expr *expr) process_insert_insn (struct expr *expr)
{ {
rtx reg = expr->reaching_reg; rtx reg = expr->reaching_reg;
/* Copy the expression to make sure we don't have any sharing issues. */
rtx exp = copy_rtx (expr->expr); rtx exp = copy_rtx (expr->expr);
rtx pat; rtx pat;
...@@ -2099,8 +2082,7 @@ process_insert_insn (struct expr *expr) ...@@ -2099,8 +2082,7 @@ process_insert_insn (struct expr *expr)
emit_move_insn (reg, exp); emit_move_insn (reg, exp);
/* Otherwise, make a new insn to compute this expression and make sure the /* Otherwise, make a new insn to compute this expression and make sure the
insn will be recognized (this also adds any needed CLOBBERs). Copy the insn will be recognized (this also adds any needed CLOBBERs). */
expression to make sure we don't have any sharing issues. */
else else
{ {
rtx insn = emit_insn (gen_rtx_SET (VOIDmode, reg, exp)); rtx insn = emit_insn (gen_rtx_SET (VOIDmode, reg, exp));
...@@ -2109,7 +2091,6 @@ process_insert_insn (struct expr *expr) ...@@ -2109,7 +2091,6 @@ process_insert_insn (struct expr *expr)
gcc_unreachable (); gcc_unreachable ();
} }
pat = get_insns (); pat = get_insns ();
end_sequence (); end_sequence ();
...@@ -2254,7 +2235,9 @@ pre_edge_insert (struct edge_list *edge_list, struct expr **index_map) ...@@ -2254,7 +2235,9 @@ pre_edge_insert (struct edge_list *edge_list, struct expr **index_map)
{ {
SBITMAP_ELT_TYPE insert = pre_insert_map[e]->elms[i]; SBITMAP_ELT_TYPE insert = pre_insert_map[e]->elms[i];
for (j = indx; insert && j < (int) expr_hash_table.n_elems; j++, insert >>= 1) for (j = indx;
insert && j < (int) expr_hash_table.n_elems;
j++, insert >>= 1)
if ((insert & 1) != 0 && index_map[j]->reaching_reg != NULL_RTX) if ((insert & 1) != 0 && index_map[j]->reaching_reg != NULL_RTX)
{ {
struct expr *expr = index_map[j]; struct expr *expr = index_map[j];
...@@ -2430,7 +2413,7 @@ pre_insert_copies (void) ...@@ -2430,7 +2413,7 @@ pre_insert_copies (void)
Need to do some profiling. */ Need to do some profiling. */
for (i = 0; i < expr_hash_table.size; i++) for (i = 0; i < expr_hash_table.size; i++)
for (expr = expr_hash_table.table[i]; expr != NULL; expr = expr->next_same_hash) for (expr = expr_hash_table.table[i]; expr; expr = expr->next_same_hash)
{ {
/* If the basic block isn't reachable, PPOUT will be TRUE. However, /* If the basic block isn't reachable, PPOUT will be TRUE. However,
we don't want to insert a copy here because the expression may not we don't want to insert a copy here because the expression may not
...@@ -2481,8 +2464,9 @@ pre_insert_copies (void) ...@@ -2481,8 +2464,9 @@ pre_insert_copies (void)
/* Emit move from SRC to DEST noting the equivalence with expression computed /* Emit move from SRC to DEST noting the equivalence with expression computed
in INSN. */ in INSN. */
static rtx static rtx
gcse_emit_move_after (rtx src, rtx dest, rtx insn) gcse_emit_move_after (rtx dest, rtx src, rtx insn)
{ {
rtx new_rtx; rtx new_rtx;
rtx set = single_set (insn), set2; rtx set = single_set (insn), set2;
...@@ -2513,7 +2497,7 @@ gcse_emit_move_after (rtx src, rtx dest, rtx insn) ...@@ -2513,7 +2497,7 @@ gcse_emit_move_after (rtx src, rtx dest, rtx insn)
the expression into the result of the SET. It is left to later passes the expression into the result of the SET. It is left to later passes
(cprop, cse2, flow, combine, regmove) to propagate the copy or eliminate it. (cprop, cse2, flow, combine, regmove) to propagate the copy or eliminate it.
Returns nonzero if a change is made. */ Return nonzero if a change is made. */
static int static int
pre_delete (void) pre_delete (void)
...@@ -2525,15 +2509,11 @@ pre_delete (void) ...@@ -2525,15 +2509,11 @@ pre_delete (void)
changed = 0; changed = 0;
for (i = 0; i < expr_hash_table.size; i++) for (i = 0; i < expr_hash_table.size; i++)
for (expr = expr_hash_table.table[i]; for (expr = expr_hash_table.table[i]; expr; expr = expr->next_same_hash)
expr != NULL;
expr = expr->next_same_hash)
{ {
int indx = expr->bitmap_index; int indx = expr->bitmap_index;
/* We only need to search antic_occr since we require /* We only need to search antic_occr since we require ANTLOC != 0. */
ANTLOC != 0. */
for (occr = expr->antic_occr; occr != NULL; occr = occr->next) for (occr = expr->antic_occr; occr != NULL; occr = occr->next)
{ {
rtx insn = occr->insn; rtx insn = occr->insn;
...@@ -2551,7 +2531,7 @@ pre_delete (void) ...@@ -2551,7 +2531,7 @@ pre_delete (void)
if (expr->reaching_reg == NULL) if (expr->reaching_reg == NULL)
expr->reaching_reg = gen_reg_rtx_and_attrs (SET_DEST (set)); expr->reaching_reg = gen_reg_rtx_and_attrs (SET_DEST (set));
gcse_emit_move_after (expr->reaching_reg, SET_DEST (set), insn); gcse_emit_move_after (SET_DEST (set), expr->reaching_reg, insn);
delete_insn (insn); delete_insn (insn);
occr->deleted_p = 1; occr->deleted_p = 1;
changed = 1; changed = 1;
...@@ -2593,7 +2573,7 @@ pre_delete (void) ...@@ -2593,7 +2573,7 @@ pre_delete (void)
redundancies. */ redundancies. */
static int static int
pre_gcse (void) pre_gcse (struct edge_list *edge_list)
{ {
unsigned int i; unsigned int i;
int did_insert, changed; int did_insert, changed;
...@@ -2605,7 +2585,7 @@ pre_gcse (void) ...@@ -2605,7 +2585,7 @@ pre_gcse (void)
index_map = XCNEWVEC (struct expr *, expr_hash_table.n_elems); index_map = XCNEWVEC (struct expr *, expr_hash_table.n_elems);
for (i = 0; i < expr_hash_table.size; i++) for (i = 0; i < expr_hash_table.size; i++)
for (expr = expr_hash_table.table[i]; expr != NULL; expr = expr->next_same_hash) for (expr = expr_hash_table.table[i]; expr; expr = expr->next_same_hash)
index_map[expr->bitmap_index] = expr; index_map[expr->bitmap_index] = expr;
/* Delete the redundant insns first so that /* Delete the redundant insns first so that
...@@ -2659,20 +2639,23 @@ one_pre_gcse_pass (void) ...@@ -2659,20 +2639,23 @@ one_pre_gcse_pass (void)
compute_ld_motion_mems (); compute_ld_motion_mems ();
compute_hash_table (&expr_hash_table); compute_hash_table (&expr_hash_table);
if (flag_gcse_lm)
trim_ld_motion_mems (); trim_ld_motion_mems ();
if (dump_file) if (dump_file)
dump_hash_table (dump_file, "Expression", &expr_hash_table); dump_hash_table (dump_file, "Expression", &expr_hash_table);
if (expr_hash_table.n_elems > 0) if (expr_hash_table.n_elems > 0)
{ {
struct edge_list *edge_list;
alloc_pre_mem (last_basic_block, expr_hash_table.n_elems); alloc_pre_mem (last_basic_block, expr_hash_table.n_elems);
compute_pre_data (); edge_list = compute_pre_data ();
changed |= pre_gcse (); changed |= pre_gcse (edge_list);
free_edge_list (edge_list); free_edge_list (edge_list);
free_pre_mem (); free_pre_mem ();
} }
free_ldst_mems (); if (flag_gcse_lm)
free_ld_motion_mems ();
remove_fake_exit_edges (); remove_fake_exit_edges ();
free_hash_table (&expr_hash_table); free_hash_table (&expr_hash_table);
...@@ -2924,6 +2907,7 @@ hoist_expr_reaches_here_p (basic_block expr_bb, int expr_index, basic_block bb, ...@@ -2924,6 +2907,7 @@ hoist_expr_reaches_here_p (basic_block expr_bb, int expr_index, basic_block bb,
} }
/* Find occurence in BB. */ /* Find occurence in BB. */
static struct occr * static struct occr *
find_occr_in_bb (struct occr *occr, basic_block bb) find_occr_in_bb (struct occr *occr, basic_block bb)
{ {
...@@ -2955,7 +2939,7 @@ hoist_code (void) ...@@ -2955,7 +2939,7 @@ hoist_code (void)
index_map = XCNEWVEC (struct expr *, expr_hash_table.n_elems); index_map = XCNEWVEC (struct expr *, expr_hash_table.n_elems);
for (i = 0; i < expr_hash_table.size; i++) for (i = 0; i < expr_hash_table.size; i++)
for (expr = expr_hash_table.table[i]; expr != NULL; expr = expr->next_same_hash) for (expr = expr_hash_table.table[i]; expr; expr = expr->next_same_hash)
index_map[expr->bitmap_index] = expr; index_map[expr->bitmap_index] = expr;
/* Calculate sizes of basic blocks and note how far /* Calculate sizes of basic blocks and note how far
...@@ -3145,7 +3129,7 @@ hoist_code (void) ...@@ -3145,7 +3129,7 @@ hoist_code (void)
expr->reaching_reg expr->reaching_reg
= gen_reg_rtx_and_attrs (SET_DEST (set)); = gen_reg_rtx_and_attrs (SET_DEST (set));
gcse_emit_move_after (expr->reaching_reg, SET_DEST (set), gcse_emit_move_after (SET_DEST (set), expr->reaching_reg,
insn); insn);
delete_insn (insn); delete_insn (insn);
occr->deleted_p = 1; occr->deleted_p = 1;
...@@ -3233,9 +3217,9 @@ one_code_hoisting_pass (void) ...@@ -3233,9 +3217,9 @@ one_code_hoisting_pass (void)
return changed; return changed;
} }
/* Here we provide the things required to do store motion towards /* Here we provide the things required to do store motion towards the exit.
the exit. In order for this to be effective, gcse also needed to In order for this to be effective, gcse also needed to be taught how to
be taught how to move a load when it is kill only by a store to itself. move a load when it is killed only by a store to itself.
int i; int i;
float a[10]; float a[10];
...@@ -3251,7 +3235,7 @@ one_code_hoisting_pass (void) ...@@ -3251,7 +3235,7 @@ one_code_hoisting_pass (void)
of the loop. of the loop.
The 'Load Motion' referred to and implemented in this file is The 'Load Motion' referred to and implemented in this file is
an enhancement to gcse which when using edge based lcm, recognizes an enhancement to gcse which when using edge based LCM, recognizes
this situation and allows gcse to move the load out of the loop. this situation and allows gcse to move the load out of the loop.
Once gcse has hoisted the load, store motion can then push this Once gcse has hoisted the load, store motion can then push this
...@@ -3263,7 +3247,8 @@ pre_ldst_expr_hash (const void *p) ...@@ -3263,7 +3247,8 @@ pre_ldst_expr_hash (const void *p)
{ {
int do_not_record_p = 0; int do_not_record_p = 0;
const struct ls_expr *const x = (const struct ls_expr *) p; const struct ls_expr *const x = (const struct ls_expr *) p;
return hash_rtx (x->pattern, GET_MODE (x->pattern), &do_not_record_p, NULL, false); return
hash_rtx (x->pattern, GET_MODE (x->pattern), &do_not_record_p, NULL, false);
} }
static int static int
...@@ -3326,7 +3311,7 @@ free_ldst_entry (struct ls_expr * ptr) ...@@ -3326,7 +3311,7 @@ free_ldst_entry (struct ls_expr * ptr)
/* Free up all memory associated with the ldst list. */ /* Free up all memory associated with the ldst list. */
static void static void
free_ldst_mems (void) free_ld_motion_mems (void)
{ {
if (pre_ldst_table) if (pre_ldst_table)
htab_delete (pre_ldst_table); htab_delete (pre_ldst_table);
...@@ -3353,7 +3338,7 @@ print_ldst_list (FILE * file) ...@@ -3353,7 +3338,7 @@ print_ldst_list (FILE * file)
fprintf (file, "LDST list: \n"); fprintf (file, "LDST list: \n");
for (ptr = first_ls_expr (); ptr != NULL; ptr = next_ls_expr (ptr)) for (ptr = pre_ldst_mems; ptr != NULL; ptr = ptr->next)
{ {
fprintf (file, " Pattern (%3d): ", ptr->index); fprintf (file, " Pattern (%3d): ", ptr->index);
...@@ -3395,34 +3380,15 @@ find_rtx_in_ldst (rtx x) ...@@ -3395,34 +3380,15 @@ find_rtx_in_ldst (rtx x)
return (struct ls_expr *) *slot; return (struct ls_expr *) *slot;
} }
/* Return first item in the list. */
static inline struct ls_expr *
first_ls_expr (void)
{
return pre_ldst_mems;
}
/* Return the next item in the list after the specified one. */
static inline struct ls_expr *
next_ls_expr (struct ls_expr * ptr)
{
return ptr->next;
}
/* Load Motion for loads which only kill themselves. */ /* Load Motion for loads which only kill themselves. */
/* Return true if x is a simple MEM operation, with no registers or /* Return true if x, a MEM, is a simple access with no side effects.
side effects. These are the types of loads we consider for the These are the types of loads we consider for the ld_motion list,
ld_motion list, otherwise we let the usual aliasing take care of it. */ otherwise we let the usual aliasing take care of it. */
static int static int
simple_mem (const_rtx x) simple_mem (const_rtx x)
{ {
if (! MEM_P (x))
return 0;
if (MEM_VOLATILE_P (x)) if (MEM_VOLATILE_P (x))
return 0; return 0;
...@@ -3499,8 +3465,8 @@ compute_ld_motion_mems (void) ...@@ -3499,8 +3465,8 @@ compute_ld_motion_mems (void)
rtx insn; rtx insn;
pre_ldst_mems = NULL; pre_ldst_mems = NULL;
pre_ldst_table = htab_create (13, pre_ldst_expr_hash, pre_ldst_table
pre_ldst_expr_eq, NULL); = htab_create (13, pre_ldst_expr_hash, pre_ldst_expr_eq, NULL);
FOR_EACH_BB (bb) FOR_EACH_BB (bb)
{ {
...@@ -3641,7 +3607,7 @@ update_ld_motion_stores (struct expr * expr) ...@@ -3641,7 +3607,7 @@ update_ld_motion_stores (struct expr * expr)
if (dump_file) if (dump_file)
{ {
fprintf (dump_file, "PRE: store updated with reaching reg "); fprintf (dump_file, "PRE: store updated with reaching reg ");
print_rtl (dump_file, expr->reaching_reg); print_rtl (dump_file, reg);
fprintf (dump_file, ":\n "); fprintf (dump_file, ":\n ");
print_inline_rtx (dump_file, insn, 8); print_inline_rtx (dump_file, insn, 8);
fprintf (dump_file, "\n"); fprintf (dump_file, "\n");
...@@ -3699,7 +3665,6 @@ is_too_expensive (const char *pass) ...@@ -3699,7 +3665,6 @@ is_too_expensive (const char *pass)
return false; return false;
} }
/* All the passes implemented in this file. Each pass has its /* All the passes implemented in this file. Each pass has its
own gate and execute function, and at the end of the file a own gate and execute function, and at the end of the file a
pass definition for passes.c. pass definition for passes.c.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment