Commit a65f3558 by Jeffrey A Law Committed by Jeff Law

gcse.c (dump_hash_table): Fix whitespace in declaration.

	* gcse.c (dump_hash_table): Fix whitespace in declaration.
	(compute_transpout): Renamed from pre_compute_transpout.
	(compute_pre_*): Deleted
	(pre_expr_reaches_here_p): New argument, CHECK_PRE_COMP.  All
	callers changed.
	(insert_insn_end_bb): Renamed from pre_insert_insn.
	(pre_*): Delete unused variables.  Only leave local properties and
	global redundant/optimal computation points.
	(alloc_pre_mem, free_pre_mem): Corresponding changes.
	(compute_pre_data): Simplify and call pre_lcm to run the lazy
	code motion dataflow analysis.
	(pre_insert, pre_insert_copies, pre_delete): Revamp to use LCM
	based redundant and optimal computation points.

From-SVN: r25886
parent 077692c6
Sun Mar 21 17:33:48 1999 Jeffrey A Law (law@cygnus.com) Sun Mar 21 17:33:48 1999 Jeffrey A Law (law@cygnus.com)
* gcse.c (dump_hash_table): Fix whitespace in declaration.
(compute_transpout): Renamed from pre_compute_transpout.
(compute_pre_*): Deleted
(pre_expr_reaches_here_p): New argument, CHECK_PRE_COMP. All
callers changed.
(insert_insn_end_bb): Renamed from pre_insert_insn.
(pre_*): Delete unused variables. Only leave local properties and
global redundant/optimal computation points.
(alloc_pre_mem, free_pre_mem): Corresponding changes.
(compute_pre_data): Simplify and call pre_lcm to run the lazy
code motion dataflow analysis.
(pre_insert, pre_insert_copies, pre_delete): Revamp to use LCM
based redundant and optimal computation points.
* basic-block.h (pre_lcm, pre_rev_lcm): Declare. * basic-block.h (pre_lcm, pre_rev_lcm): Declare.
* toplev.c (main): A debug option without a level defaults to * toplev.c (main): A debug option without a level defaults to
......
...@@ -550,7 +550,8 @@ static void compute_set_hash_table PROTO ((void)); ...@@ -550,7 +550,8 @@ static void compute_set_hash_table PROTO ((void));
static void alloc_expr_hash_table PROTO ((int)); static void alloc_expr_hash_table PROTO ((int));
static void free_expr_hash_table PROTO ((void)); static void free_expr_hash_table PROTO ((void));
static void compute_expr_hash_table PROTO ((void)); static void compute_expr_hash_table PROTO ((void));
static void dump_hash_table PROTO ((FILE *, const char *, struct expr **, int, int)); static void dump_hash_table PROTO ((FILE *, const char *, struct expr **,
int, int));
static struct expr *lookup_expr PROTO ((rtx)); static struct expr *lookup_expr PROTO ((rtx));
static struct expr *lookup_set PROTO ((int, rtx)); static struct expr *lookup_set PROTO ((int, rtx));
static struct expr *next_set PROTO ((int, struct expr *)); static struct expr *next_set PROTO ((int, struct expr *));
...@@ -564,6 +565,7 @@ static void mark_oprs_set PROTO ((rtx)); ...@@ -564,6 +565,7 @@ static void mark_oprs_set PROTO ((rtx));
static void alloc_cprop_mem PROTO ((int, int)); static void alloc_cprop_mem PROTO ((int, int));
static void free_cprop_mem PROTO ((void)); static void free_cprop_mem PROTO ((void));
static void compute_transp PROTO ((rtx, int, sbitmap *, int)); static void compute_transp PROTO ((rtx, int, sbitmap *, int));
static void compute_transpout PROTO ((void));
static void compute_local_properties PROTO ((sbitmap *, sbitmap *, static void compute_local_properties PROTO ((sbitmap *, sbitmap *,
sbitmap *, int)); sbitmap *, int));
static void compute_cprop_avinout PROTO ((void)); static void compute_cprop_avinout PROTO ((void));
...@@ -577,14 +579,10 @@ static int one_cprop_pass PROTO ((int, int)); ...@@ -577,14 +579,10 @@ static int one_cprop_pass PROTO ((int, int));
static void alloc_pre_mem PROTO ((int, int)); static void alloc_pre_mem PROTO ((int, int));
static void free_pre_mem PROTO ((void)); static void free_pre_mem PROTO ((void));
static void compute_pre_avinout PROTO ((void));
static void compute_pre_antinout PROTO ((void));
static void compute_pre_pavinout PROTO ((void));
static void compute_pre_ppinout PROTO ((void));
static void compute_pre_data PROTO ((void)); static void compute_pre_data PROTO ((void));
static int pre_expr_reaches_here_p PROTO ((struct occr *, struct expr *, static int pre_expr_reaches_here_p PROTO ((int, struct expr *,
int, char *)); int, int, char *));
static void pre_insert_insn PROTO ((struct expr *, int)); static void insert_insn_end_bb PROTO ((struct expr *, int, int));
static void pre_insert PROTO ((struct expr **)); static void pre_insert PROTO ((struct expr **));
static void pre_insert_copy_insn PROTO ((struct expr *, rtx)); static void pre_insert_copy_insn PROTO ((struct expr *, rtx));
static void pre_insert_copies PROTO ((void)); static void pre_insert_copies PROTO ((void));
...@@ -3924,339 +3922,63 @@ one_cprop_pass (pass, alter_jumps) ...@@ -3924,339 +3922,63 @@ one_cprop_pass (pass, alter_jumps)
return changed; return changed;
} }
/* Compute PRE 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 *pre_transp; static sbitmap *transp;
/* Nonzero for expressions that are computed (available) in the block. */
static sbitmap *pre_comp;
/* Nonzero for expressions that are locally anticipatable in the block. */
static sbitmap *pre_antloc;
/* Global properties (computed from the expression local properties). */
/* Nonzero for expressions that are available on block entry/exit. */
static sbitmap *pre_avin;
static sbitmap *pre_avout;
/* Nonzero for expressions that are anticipatable on block entry/exit. */
static sbitmap *pre_antin;
static sbitmap *pre_antout;
/* Nonzero for expressions that are partially available on block entry/exit. */
static sbitmap *pre_pavin;
static sbitmap *pre_pavout;
/* Nonzero for expressions that are "placement possible" on block entry/exit. */
static sbitmap *pre_ppin;
static sbitmap *pre_ppout;
/* Nonzero for expressions that are transparent at the end of the block. /* Nonzero for expressions that are transparent at the end of the block.
This is only zero for expressions killed by abnormal critical edge This is only zero for expressions killed by abnormal critical edge
created by a calls. */ created by a calls. */
static sbitmap *pre_transpout; static sbitmap *transpout;
/* Used while performing PRE to denote which insns are redundant. */ /* Nonzero for expressions that are computed (available) in the block. */
static sbitmap pre_redundant; static sbitmap *comp;
/* Allocate vars used for PRE analysis. */
static void
alloc_pre_mem (n_blocks, n_exprs)
int n_blocks, n_exprs;
{
pre_transp = sbitmap_vector_alloc (n_blocks, n_exprs);
pre_comp = sbitmap_vector_alloc (n_blocks, n_exprs);
pre_antloc = sbitmap_vector_alloc (n_blocks, n_exprs);
pre_avin = sbitmap_vector_alloc (n_blocks, n_exprs); /* Nonzero for expressions that are locally anticipatable in the block. */
pre_avout = sbitmap_vector_alloc (n_blocks, n_exprs); static sbitmap *antloc;
pre_antin = sbitmap_vector_alloc (n_blocks, n_exprs);
pre_antout = sbitmap_vector_alloc (n_blocks, n_exprs);
pre_pavin = sbitmap_vector_alloc (n_blocks, n_exprs); /* Nonzero for expressions where this block is an optimal computation
pre_pavout = sbitmap_vector_alloc (n_blocks, n_exprs); point. */
pre_ppin = sbitmap_vector_alloc (n_blocks, n_exprs); static sbitmap *pre_optimal;
pre_ppout = sbitmap_vector_alloc (n_blocks, n_exprs);
pre_transpout = sbitmap_vector_alloc (n_blocks, n_exprs); /* Nonzero for expressions which are redundant in a particular block. */
} static sbitmap *pre_redundant;
/* Free vars used for PRE analysis. */ static sbitmap *temp_bitmap;
static void /* Redundant insns. */
free_pre_mem () static sbitmap pre_redundant_insns;
{
free (pre_transp);
free (pre_comp);
free (pre_antloc);
free (pre_avin);
free (pre_avout);
free (pre_antin);
free (pre_antout);
free (pre_pavin);
free (pre_pavout);
free (pre_ppin);
free (pre_ppout);
free (pre_transpout);
}
/* Compute expression availability at entrance and exit of each block. */ /* Allocate vars used for PRE analysis. */
static void
compute_pre_avinout ()
{
int bb, changed, passes;
sbitmap_zero (pre_avin[0]);
sbitmap_vector_ones (pre_avout, n_basic_blocks);
passes = 0;
changed = 1;
while (changed)
{
changed = 0;
for (bb = 0; bb < n_basic_blocks; bb++)
{
if (bb != 0)
sbitmap_intersect_of_predecessors (pre_avin[bb], pre_avout,
bb, s_preds);
changed |= sbitmap_a_or_b_and_c (pre_avout[bb], pre_comp[bb],
pre_transp[bb], pre_avin[bb]);
}
passes++;
}
if (gcse_file)
fprintf (gcse_file, "avail expr computation: %d passes\n", passes);
}
/* Compute expression anticipatability at entrance and exit of each block. */
static void static void
compute_pre_antinout () alloc_pre_mem (n_blocks, n_exprs)
int n_blocks, n_exprs;
{ {
int bb, changed, passes; transp = sbitmap_vector_alloc (n_blocks, n_exprs);
comp = sbitmap_vector_alloc (n_blocks, n_exprs);
sbitmap_zero (pre_antout[n_basic_blocks - 1]); antloc = sbitmap_vector_alloc (n_blocks, n_exprs);
sbitmap_vector_ones (pre_antin, n_basic_blocks);
temp_bitmap = sbitmap_vector_alloc (n_blocks, n_exprs);
passes = 0; pre_optimal = sbitmap_vector_alloc (n_blocks, n_exprs);
changed = 1; pre_redundant = sbitmap_vector_alloc (n_blocks, n_exprs);
while (changed) transpout = sbitmap_vector_alloc (n_blocks, n_exprs);
{
changed = 0;
/* We scan the blocks in the reverse order to speed up
the convergence. */
for (bb = n_basic_blocks - 1; bb >= 0; bb--)
{
if (bb != n_basic_blocks - 1)
sbitmap_intersect_of_successors (pre_antout[bb], pre_antin,
bb, s_succs);
changed |= sbitmap_a_or_b_and_c (pre_antin[bb], pre_antloc[bb],
pre_transp[bb], pre_antout[bb]);
}
passes++;
}
if (gcse_file)
fprintf (gcse_file, "antic expr computation: %d passes\n", passes);
} }
/* Compute expression partial availability at entrance and exit of /* Free vars used for PRE analysis. */
each block. */
static void
compute_pre_pavinout ()
{
int bb, changed, passes;
sbitmap_zero (pre_pavin[0]);
sbitmap_vector_zero (pre_pavout, n_basic_blocks);
passes = 0;
changed = 1;
while (changed)
{
changed = 0;
for (bb = 0; bb < n_basic_blocks; bb++)
{
if (bb != 0)
sbitmap_union_of_predecessors (pre_pavin[bb], pre_pavout,
bb, s_preds);
changed |= sbitmap_a_or_b_and_c (pre_pavout[bb], pre_comp[bb],
pre_transp[bb], pre_pavin[bb]);
}
passes++;
}
if (gcse_file)
fprintf (gcse_file, "partially avail expr computation: %d passes\n", passes);
}
/* Compute transparent outgoing information for each block.
An expression is transparent to an edge unless it is killed by
the edge itself. This can only happen with abnormal control flow,
when the edge is traversed through a call. This happens with
non-local labels and exceptions.
This would not be necessary if we split the edge. While this is
normally impossible for abnormal critical edges, with some effort
it should be possible with exception handling, since we still have
control over which handler should be invoked. But due to increased
EH table sizes, this may not be worthwhile. */
static void
compute_pre_transpout ()
{
int bb;
sbitmap_vector_ones (pre_transpout, n_basic_blocks);
for (bb = 0; bb < n_basic_blocks; ++bb)
{
int i;
/* Note that flow inserted a nop a the end of basic blocks that
end in call instructions for reasons other than abnormal
control flow. */
if (GET_CODE (BLOCK_END (bb)) != CALL_INSN)
continue;
for (i = 0; i < expr_hash_table_size; i++)
{
struct expr *expr;
for (expr = expr_hash_table[i]; expr ; expr = expr->next_same_hash)
if (GET_CODE (expr->expr) == MEM)
{
rtx addr = XEXP (expr->expr, 0);
if (GET_CODE (addr) == SYMBOL_REF
&& CONSTANT_POOL_ADDRESS_P (addr))
continue;
/* ??? Optimally, we would use interprocedural alias
analysis to determine if this mem is actually killed
by this call. */
RESET_BIT (pre_transpout[bb], expr->bitmap_index);
}
}
}
}
/* Compute "placement possible" information on entrance and exit of
each block.
From Fred Chow's Thesis:
A computation `e' is PP at a point `p' if it is anticipated at `p' and
all the anticipated e's can be rendered redundant by zero or more
insertions at that point and some other points in the procedure, and
these insertions satisfy the conditions that the insertions are always
at points that `e' is anticipated and the first anticipated e's after the
insertions are rendered redundant. */
static void static void
compute_pre_ppinout () free_pre_mem ()
{ {
int bb, i, changed, size, passes; free (transp);
free (comp);
sbitmap_vector_ones (pre_ppin, n_basic_blocks); free (antloc);
/* ??? Inefficient as we set pre_ppin[0] twice, but simple. */
sbitmap_zero (pre_ppin[0]);
sbitmap_vector_ones (pre_ppout, n_basic_blocks);
/* ??? Inefficient as we set pre_ppout[n_basic_blocks-1] twice, but simple. */
sbitmap_zero (pre_ppout[n_basic_blocks - 1]);
size = pre_ppin[0]->size;
passes = 0;
changed = 1;
while (changed)
{
changed = 0;
for (bb = 1; bb < n_basic_blocks; bb++)
{
sbitmap_ptr antin = pre_antin[bb]->elms;
sbitmap_ptr pavin = pre_pavin[bb]->elms;
sbitmap_ptr antloc = pre_antloc[bb]->elms;
sbitmap_ptr transp = pre_transp[bb]->elms;
sbitmap_ptr ppout = pre_ppout[bb]->elms;
sbitmap_ptr ppin = pre_ppin[bb]->elms;
for (i = 0; i < size; i++)
{
int_list_ptr pred;
SBITMAP_ELT_TYPE tmp = *antin & *pavin & (*antloc | (*transp & *ppout));
SBITMAP_ELT_TYPE pred_val = (SBITMAP_ELT_TYPE) -1;
for (pred = s_preds[bb]; pred != NULL; pred = pred->next)
{
int pred_bb = INT_LIST_VAL (pred);
sbitmap_ptr ppout_j,avout_j;
if (pred_bb == ENTRY_BLOCK)
continue;
/* If this is a back edge, propagate info along the back
edge to allow for loop invariant code motion.
See FOLLOW_BACK_EDGES at the top of this file for a longer
discussion about loop invariant code motion in pre. */
if (! FOLLOW_BACK_EDGES
&& (INSN_CUID (BLOCK_HEAD (bb))
< INSN_CUID (BLOCK_END (pred_bb))))
{
pred_val = 0;
}
else
{
ppout_j = pre_ppout[pred_bb]->elms + i;
avout_j = pre_avout[pred_bb]->elms + i;
pred_val &= *ppout_j | *avout_j;
}
}
tmp &= pred_val;
*ppin = tmp;
antin++; pavin++; antloc++; transp++; ppout++; ppin++;
}
}
for (bb = 0; bb < n_basic_blocks - 1; bb++)
{
sbitmap_ptr ppout = pre_ppout[bb]->elms;
sbitmap_ptr transpout = pre_transpout[bb]->elms;
for (i = 0; i < size; i++)
{
int_list_ptr succ;
SBITMAP_ELT_TYPE tmp = *transpout;
for (succ = s_succs[bb]; succ != NULL; succ = succ->next)
{
int succ_bb = INT_LIST_VAL (succ);
sbitmap_ptr ppin;
if (succ_bb == EXIT_BLOCK)
continue;
ppin = pre_ppin[succ_bb]->elms + i;
tmp &= *ppin;
}
if (*ppout != tmp)
{
changed = 1;
*ppout = tmp;
}
ppout++; transpout++;
}
}
passes++;
}
if (gcse_file) free (pre_optimal);
fprintf (gcse_file, "placement possible computation: %d passes\n", passes); free (pre_redundant);
free (transpout);
} }
/* Top level routine to do the dataflow analysis needed by PRE. */ /* Top level routine to do the dataflow analysis needed by PRE. */
...@@ -4264,23 +3986,24 @@ compute_pre_ppinout () ...@@ -4264,23 +3986,24 @@ compute_pre_ppinout ()
static void static void
compute_pre_data () compute_pre_data ()
{ {
compute_local_properties (pre_transp, pre_comp, pre_antloc, 0); compute_local_properties (transp, comp, antloc, 0);
compute_pre_avinout (); compute_transpout ();
compute_pre_antinout (); pre_lcm (n_basic_blocks, n_exprs, s_preds, s_succs, transp,
compute_pre_pavinout (); antloc, pre_redundant, pre_optimal);
compute_pre_transpout ();
compute_pre_ppinout ();
if (gcse_file)
fprintf (gcse_file, "\n");
} }
/* PRE utilities */ /* PRE utilities */
/* Return non-zero if occurrence OCCR of expression EXPR reaches block BB. /* Return non-zero if an occurrence of expression EXPR in OCCR_BB would reach
block BB.
VISITED is a pointer to a working buffer for tracking which BB's have VISITED is a pointer to a working buffer for tracking which BB's have
been visited. It is NULL for the top-level call. been visited. It is NULL for the top-level call.
CHECK_PRE_COMP controls whether or not we check for a computation of
EXPR in OCCR_BB.
We treat reaching expressions that go through blocks containing the same We treat reaching expressions that go through blocks containing the same
reaching expression as "not reaching". E.g. if EXPR is generated in blocks reaching expression as "not reaching". E.g. if EXPR is generated in blocks
2 and 3, INSN is in block 4, and 2->3->4, we treat the expression in block 2 and 3, INSN is in block 4, and 2->3->4, we treat the expression in block
...@@ -4289,10 +4012,11 @@ compute_pre_data () ...@@ -4289,10 +4012,11 @@ compute_pre_data ()
the closest such expression. */ the closest such expression. */
static int static int
pre_expr_reaches_here_p (occr, expr, bb, visited) pre_expr_reaches_here_p (occr_bb, expr, bb, check_pre_comp, visited)
struct occr *occr; int occr_bb;
struct expr *expr; struct expr *expr;
int bb; int bb;
int check_pre_comp;
char *visited; char *visited;
{ {
int_list_ptr pred; int_list_ptr pred;
...@@ -4314,23 +4038,25 @@ pre_expr_reaches_here_p (occr, expr, bb, visited) ...@@ -4314,23 +4038,25 @@ pre_expr_reaches_here_p (occr, expr, bb, visited)
/* Nothing to do. */ /* Nothing to do. */
} }
/* Does this predecessor generate this expression? */ /* Does this predecessor generate this expression? */
else if (TEST_BIT (pre_comp[pred_bb], expr->bitmap_index)) else if ((!check_pre_comp && occr_bb == pred_bb)
|| TEST_BIT (comp[pred_bb], expr->bitmap_index))
{ {
/* Is this the occurrence we're looking for? /* Is this the occurrence we're looking for?
Note that there's only one generating occurrence per block Note that there's only one generating occurrence per block
so we just need to check the block number. */ so we just need to check the block number. */
if (BLOCK_NUM (occr->insn) == pred_bb) if (occr_bb == pred_bb)
return 1; return 1;
visited[pred_bb] = 1; visited[pred_bb] = 1;
} }
/* Ignore this predecessor if it kills the expression. */ /* Ignore this predecessor if it kills the expression. */
else if (! TEST_BIT (pre_transp[pred_bb], expr->bitmap_index)) else if (! TEST_BIT (transp[pred_bb], expr->bitmap_index))
visited[pred_bb] = 1; visited[pred_bb] = 1;
/* Neither gen nor kill. */ /* Neither gen nor kill. */
else else
{ {
visited[pred_bb] = 1; visited[pred_bb] = 1;
if (pre_expr_reaches_here_p (occr, expr, pred_bb, visited)) if (pre_expr_reaches_here_p (occr_bb, expr, pred_bb,
check_pre_comp, visited))
return 1; return 1;
} }
} }
...@@ -4339,20 +4065,33 @@ pre_expr_reaches_here_p (occr, expr, bb, visited) ...@@ -4339,20 +4065,33 @@ pre_expr_reaches_here_p (occr, expr, bb, visited)
return 0; return 0;
} }
/* Add EXPR to the end of basic block BB. */ /* Add EXPR to the end of basic block BB.
This is used by both the PRE and code hoisting.
For PRE, we want to verify that the expr is either transparent
or locally anticipatable in the target block. This check makes
no sense for code hoisting. */
static void static void
pre_insert_insn (expr, bb) insert_insn_end_bb (expr, bb, pre)
struct expr *expr; struct expr *expr;
int bb; int bb;
int pre;
{ {
rtx insn = BLOCK_END (bb); rtx insn = BLOCK_END (bb);
rtx new_insn; rtx new_insn;
rtx reg = expr->reaching_reg; rtx reg = expr->reaching_reg;
int regno = REGNO (reg); int regno = REGNO (reg);
rtx pat; rtx pat, copied_expr;
rtx first_new_insn;
pat = gen_rtx_SET (VOIDmode, reg, copy_rtx (expr->expr)); start_sequence ();
copied_expr = copy_rtx (expr->expr);
emit_move_insn (reg, copied_expr);
first_new_insn = get_insns ();
pat = gen_sequence ();
end_sequence ();
/* If the last insn is a jump, insert EXPR in front [taking care to /* If the last insn is a jump, insert EXPR in front [taking care to
handle cc0, etc. properly]. */ handle cc0, etc. properly]. */
...@@ -4387,7 +4126,6 @@ pre_insert_insn (expr, bb) ...@@ -4387,7 +4126,6 @@ pre_insert_insn (expr, bb)
#endif #endif
/* FIXME: What if something in cc0/jump uses value set in new insn? */ /* FIXME: What if something in cc0/jump uses value set in new insn? */
new_insn = emit_insn_before (pat, insn); new_insn = emit_insn_before (pat, insn);
add_label_notes (SET_SRC (pat), new_insn);
if (BLOCK_HEAD (bb) == insn) if (BLOCK_HEAD (bb) == insn)
BLOCK_HEAD (bb) = new_insn; BLOCK_HEAD (bb) = new_insn;
} }
...@@ -4405,11 +4143,11 @@ pre_insert_insn (expr, bb) ...@@ -4405,11 +4143,11 @@ pre_insert_insn (expr, bb)
presumtion that we'll get better code elsewhere as well. */ presumtion that we'll get better code elsewhere as well. */
/* It should always be the case that we can put these instructions /* It should always be the case that we can put these instructions
anywhere in the basic block. Check this. */ anywhere in the basic block with performing PRE optimizations.
/* ??? Well, it would be the case if we'd split all critical edges. Check this. */
Since we didn't, we may very well abort. */ if (pre
if (!TEST_BIT (pre_antloc[bb], expr->bitmap_index) && !TEST_BIT (antloc[bb], expr->bitmap_index)
&& !TEST_BIT (pre_transp[bb], expr->bitmap_index)) && !TEST_BIT (transp[bb], expr->bitmap_index))
abort (); abort ();
/* Since different machines initialize their parameter registers /* Since different machines initialize their parameter registers
...@@ -4449,62 +4187,101 @@ pre_insert_insn (expr, bb) ...@@ -4449,62 +4187,101 @@ pre_insert_insn (expr, bb)
else else
{ {
new_insn = emit_insn_after (pat, insn); new_insn = emit_insn_after (pat, insn);
add_label_notes (SET_SRC (pat), new_insn);
BLOCK_END (bb) = new_insn; BLOCK_END (bb) = new_insn;
} }
/* Keep block number table up to date. */ /* Keep block number table up to date.
set_block_num (new_insn, bb); Note, PAT could be a multiple insn sequence, we have to make
/* Keep register set table up to date. */ sure that each insn in the sequence is handled. */
record_one_set (regno, new_insn); if (GET_CODE (pat) == SEQUENCE)
{
int i;
for (i = 0; i < XVECLEN (pat, 0); i++)
{
rtx insn = XVECEXP (pat, 0, i);
set_block_num (insn, bb);
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
add_label_notes (PATTERN (insn), new_insn);
record_set_insn = insn;
note_stores (PATTERN (insn), record_set_info);
}
}
else
{
add_label_notes (SET_SRC (pat), new_insn);
set_block_num (new_insn, bb);
/* Keep register set table up to date. */
record_one_set (regno, new_insn);
}
gcse_create_count++; gcse_create_count++;
if (gcse_file) if (gcse_file)
{ {
fprintf (gcse_file, "PRE: end of bb %d, insn %d, copying expression %d to reg %d\n", fprintf (gcse_file, "PRE/HOIST: end of bb %d, insn %d, copying expression %d to reg %d\n",
bb, INSN_UID (new_insn), expr->bitmap_index, regno); bb, INSN_UID (new_insn), expr->bitmap_index, regno);
} }
} }
/* Insert partially redundant expressions at the ends of appropriate basic /* Insert partially redundant expressions at the ends of appropriate basic
blocks making them now redundant. */ blocks making them fully redundant. */
static void static void
pre_insert (index_map) pre_insert (index_map)
struct expr **index_map; struct expr **index_map;
{ {
int bb, i, size; int bb, i, set_size;
sbitmap *inserted;
/* Compute INSERT = PRE_OPTIMAL & ~PRE_REDUNDANT.
Where INSERT is nonzero, we add the expression at the end of the basic
block if it reaches any of the deleted expressions. */
/* Compute INSERT = PPOUT & (~AVOUT) & (~PPIN | ~TRANSP) for each set_size = pre_optimal[0]->size;
expression. Where INSERT == TRUE, add the expression at the end of inserted = sbitmap_vector_alloc (n_basic_blocks, n_exprs);
the basic block. */ sbitmap_vector_zero (inserted, n_basic_blocks);
size = pre_ppout[0]->size;
for (bb = 0; bb < n_basic_blocks; bb++) for (bb = 0; bb < n_basic_blocks; bb++)
{ {
int indx; int indx;
sbitmap_ptr ppout = pre_ppout[bb]->elms;
sbitmap_ptr avout = pre_avout[bb]->elms; /* This computes the number of potential insertions we need. */
sbitmap_ptr ppin = pre_ppin[bb]->elms; sbitmap_not (temp_bitmap[bb], pre_redundant[bb]);
sbitmap_ptr transp = pre_transp[bb]->elms; sbitmap_a_and_b (temp_bitmap[bb], temp_bitmap[bb], pre_optimal[bb]);
for (i = indx = 0; /* TEMP_BITMAP[bb] now contains a bitmap of the expressions that we need
i < size; to insert at the end of this basic block. */
i++, indx += SBITMAP_ELT_BITS, ppout++, avout++, ppin++, transp++) for (i = indx = 0; i < set_size; i++, indx += SBITMAP_ELT_BITS)
{ {
SBITMAP_ELT_TYPE insert = temp_bitmap[bb]->elms[i];
int j; int j;
SBITMAP_ELT_TYPE insert = *ppout & (~*avout) & (~*ppin | ~*transp);
for (j = indx; insert != 0 && j < n_exprs; j++, insert >>= 1) for (j = indx; insert && j < n_exprs; j++, insert >>= 1)
{ {
if ((insert & 1) != 0 if ((insert & 1) != 0 && index_map[j]->reaching_reg != NULL_RTX)
/* If the basic block isn't reachable, PPOUT will be TRUE. {
However, we don't want to insert a copy here because the struct expr *expr = index_map[j];
expression may not really be redundant. So only insert struct occr *occr;
an insn if the expression was deleted. */
&& index_map[j]->reaching_reg != NULL) /* Now look at each deleted occurence of this expression. */
pre_insert_insn (index_map[j], bb); for (occr = expr->antic_occr; occr != NULL; occr = occr->next)
{
if (! occr->deleted_p)
continue;
/* Insert this expression at the end of BB if it would
reach the deleted occurence. */
if (!TEST_BIT (inserted[bb], j)
&& pre_expr_reaches_here_p (bb, expr,
BLOCK_NUM (occr->insn), 0,
NULL))
{
SET_BIT (inserted[bb], j);
insert_insn_end_bb (index_map[j], bb, 1);
}
}
}
} }
} }
} }
...@@ -4548,7 +4325,12 @@ pre_insert_copy_insn (expr, insn) ...@@ -4548,7 +4325,12 @@ pre_insert_copy_insn (expr, insn)
static void static void
pre_insert_copies () pre_insert_copies ()
{ {
int i; int i, bb;
for (bb = 0; bb < n_basic_blocks; bb++)
{
sbitmap_a_and_b (temp_bitmap[bb], pre_optimal[bb], pre_redundant[bb]);
}
/* For each available expression in the table, copy the result to /* For each available expression in the table, copy the result to
`reaching_reg' if the expression reaches a deleted one. `reaching_reg' if the expression reaches a deleted one.
...@@ -4583,17 +4365,21 @@ pre_insert_copies () ...@@ -4583,17 +4365,21 @@ pre_insert_copies ()
for (avail = expr->avail_occr; avail != NULL; avail = avail->next) for (avail = expr->avail_occr; avail != NULL; avail = avail->next)
{ {
rtx insn = avail->insn; rtx insn = avail->insn;
int bb = BLOCK_NUM (insn);
if (!TEST_BIT (temp_bitmap[bb], expr->bitmap_index))
continue;
/* No need to handle this one if handled already. */ /* No need to handle this one if handled already. */
if (avail->copied_p) if (avail->copied_p)
continue; continue;
/* Don't handle this one if it's a redundant one. */ /* Don't handle this one if it's a redundant one. */
if (TEST_BIT (pre_redundant, INSN_CUID (insn))) if (TEST_BIT (pre_redundant_insns, INSN_CUID (insn)))
continue; continue;
/* Or if the expression doesn't reach the deleted one. */ /* Or if the expression doesn't reach the deleted one. */
if (! pre_expr_reaches_here_p (avail, expr, if (! pre_expr_reaches_here_p (BLOCK_NUM (avail->insn), expr,
BLOCK_NUM (occr->insn), BLOCK_NUM (occr->insn),
NULL)) 1, NULL))
continue; continue;
/* Copy the result of avail to reaching_reg. */ /* Copy the result of avail to reaching_reg. */
...@@ -4606,7 +4392,6 @@ pre_insert_copies () ...@@ -4606,7 +4392,6 @@ pre_insert_copies ()
} }
/* Delete redundant computations. /* Delete redundant computations.
These are ones that satisy ANTLOC & PPIN.
Deletion is done by changing the insn to copy the `reaching_reg' of Deletion is done by changing the insn to copy the `reaching_reg' of
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.
...@@ -4616,7 +4401,15 @@ pre_insert_copies () ...@@ -4616,7 +4401,15 @@ pre_insert_copies ()
static int static int
pre_delete () pre_delete ()
{ {
int i, changed; int i, bb, changed;
/* Compute the expressions which are redundant and need to be replaced by
copies from the reaching reg to the target reg. */
for (bb = 0; bb < n_basic_blocks; bb++)
{
sbitmap_not (temp_bitmap[bb], pre_optimal[bb]);
sbitmap_a_and_b (temp_bitmap[bb], temp_bitmap[bb], pre_redundant[bb]);
}
changed = 0; changed = 0;
for (i = 0; i < expr_hash_table_size; i++) for (i = 0; i < expr_hash_table_size; i++)
...@@ -4636,9 +4429,8 @@ pre_delete () ...@@ -4636,9 +4429,8 @@ pre_delete ()
rtx insn = occr->insn; rtx insn = occr->insn;
rtx set; rtx set;
int bb = BLOCK_NUM (insn); int bb = BLOCK_NUM (insn);
sbitmap ppin = pre_ppin[bb];
if (TEST_BIT (ppin, indx)) if (TEST_BIT (temp_bitmap[bb], indx))
{ {
set = single_set (insn); set = single_set (insn);
if (! set) if (! set)
...@@ -4662,14 +4454,15 @@ pre_delete () ...@@ -4662,14 +4454,15 @@ pre_delete ()
expr->reaching_reg, 0)) expr->reaching_reg, 0))
{ {
occr->deleted_p = 1; occr->deleted_p = 1;
SET_BIT (pre_redundant, INSN_CUID (insn)); SET_BIT (pre_redundant_insns, INSN_CUID (insn));
changed = 1; changed = 1;
gcse_subst_count++; gcse_subst_count++;
} }
if (gcse_file) if (gcse_file)
{ {
fprintf (gcse_file, "PRE: redundant insn %d (expression %d) in bb %d, reaching reg is %d\n", fprintf (gcse_file,
"PRE: redundant insn %d (expression %d) in bb %d, reaching reg is %d\n",
INSN_UID (insn), indx, bb, REGNO (expr->reaching_reg)); INSN_UID (insn), indx, bb, REGNO (expr->reaching_reg));
} }
} }
...@@ -4684,10 +4477,9 @@ pre_delete () ...@@ -4684,10 +4477,9 @@ pre_delete ()
This is called by one_pre_gcse_pass after all the dataflow analysis This is called by one_pre_gcse_pass after all the dataflow analysis
has been done. has been done.
This is based on the original Morel-Renvoise paper and Fred Chow's thesis. This is based on the original Morel-Renvoise paper Fred Chow's thesis,
and lazy code motion from Knoop, Ruthing and Steffen as described in
The M-R paper uses "TRANSP" to describe an expression as being transparent Advanced Compiler Design and Implementation.
in a block where as Chow's thesis uses "ALTERED". We use TRANSP.
??? A new pseudo reg is created to hold the reaching expression. ??? A new pseudo reg is created to hold the reaching expression.
The nice thing about the classical approach is that it would try to The nice thing about the classical approach is that it would try to
...@@ -4722,8 +4514,8 @@ pre_gcse () ...@@ -4722,8 +4514,8 @@ pre_gcse ()
} }
/* Reset bitmap used to track which insns are redundant. */ /* Reset bitmap used to track which insns are redundant. */
pre_redundant = sbitmap_alloc (max_cuid); pre_redundant_insns = sbitmap_alloc (max_cuid);
sbitmap_zero (pre_redundant); sbitmap_zero (pre_redundant_insns);
/* Delete the redundant insns first so that /* Delete the redundant insns first so that
- we know what register to use for the new insns and for the other - we know what register to use for the new insns and for the other
...@@ -4739,7 +4531,7 @@ pre_gcse () ...@@ -4739,7 +4531,7 @@ pre_gcse ()
specially allocated pseudo-reg that reaches the redundant expression. */ specially allocated pseudo-reg that reaches the redundant expression. */
pre_insert_copies (); pre_insert_copies ();
free (pre_redundant); free (pre_redundant_insns);
return changed; return changed;
} }
...@@ -4824,3 +4616,54 @@ add_label_notes (x, insn) ...@@ -4824,3 +4616,54 @@ add_label_notes (x, insn)
add_label_notes (XVECEXP (x, i, j), insn); add_label_notes (XVECEXP (x, i, j), insn);
} }
} }
/* Compute transparent outgoing information for each block.
An expression is transparent to an edge unless it is killed by
the edge itself. This can only happen with abnormal control flow,
when the edge is traversed through a call. This happens with
non-local labels and exceptions.
This would not be necessary if we split the edge. While this is
normally impossible for abnormal critical edges, with some effort
it should be possible with exception handling, since we still have
control over which handler should be invoked. But due to increased
EH table sizes, this may not be worthwhile. */
static void
compute_transpout ()
{
int bb;
sbitmap_vector_ones (transpout, n_basic_blocks);
for (bb = 0; bb < n_basic_blocks; ++bb)
{
int i;
/* Note that flow inserted a nop a the end of basic blocks that
end in call instructions for reasons other than abnormal
control flow. */
if (GET_CODE (BLOCK_END (bb)) != CALL_INSN)
continue;
for (i = 0; i < expr_hash_table_size; i++)
{
struct expr *expr;
for (expr = expr_hash_table[i]; expr ; expr = expr->next_same_hash)
if (GET_CODE (expr->expr) == MEM)
{
rtx addr = XEXP (expr->expr, 0);
if (GET_CODE (addr) == SYMBOL_REF
&& CONSTANT_POOL_ADDRESS_P (addr))
continue;
/* ??? Optimally, we would use interprocedural alias
analysis to determine if this mem is actually killed
by this call. */
RESET_BIT (transpout[bb], expr->bitmap_index);
}
}
}
}
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