Commit 384d7a55 by Steven Bosscher

cprop.c (implicit_set_cond_p): Assume nothing about COND...

	* cprop.c (implicit_set_cond_p): Assume nothing about COND, move
	checks on form of COND from find_implicit_sets to here.
	(find_implicit_sets): Cleanup control flow. Split critical edges
	if it exposes implicit sets.  Allocate/resize implicit_sets as
	necessary.
	(one_cprop_pass): Only delete unreachable blocks if local_cprop_pass
	changed something.  Run df_analyze after find_implicit_sets if any
	edges were split.  Do not allocate implicit_sets here.

From-SVN: r171946
parent 3084ce69
2011-04-04 Steven Bosscher <steven@gcc.gnu.org> 2011-04-04 Steven Bosscher <steven@gcc.gnu.org>
* cprop.c (implicit_set_cond_p): Assume nothing about COND, move
checks on form of COND from find_implicit_sets to here.
(find_implicit_sets): Cleanup control flow. Split critical edges
if it exposes implicit sets. Allocate/resize implicit_sets as
necessary.
(one_cprop_pass): Only delete unreachable blocks if local_cprop_pass
changed something. Run df_analyze after find_implicit_sets if any
edges were split. Do not allocate implicit_sets here.
* cprop.c: s/gcse/cprop/ everywhere except for flag_gcse. * cprop.c: s/gcse/cprop/ everywhere except for flag_gcse.
(gcse_obstack): Renamed to cprop_obstack. (gcse_obstack): Renamed to cprop_obstack.
(GNEW, GNEWVEC, GNEWVAR): Remove. (GNEW, GNEWVEC, GNEWVAR): Remove.
......
...@@ -1343,14 +1343,27 @@ fis_get_condition (rtx jump) ...@@ -1343,14 +1343,27 @@ fis_get_condition (rtx jump)
return get_condition (jump, NULL, false, true); return get_condition (jump, NULL, false, true);
} }
/* Check the comparison COND to see if we can safely form an implicit set from /* Check the comparison COND to see if we can safely form an implicit
it. COND is either an EQ or NE comparison. */ set from it. */
static bool static bool
implicit_set_cond_p (const_rtx cond) implicit_set_cond_p (const_rtx cond)
{ {
const enum machine_mode mode = GET_MODE (XEXP (cond, 0)); enum machine_mode mode;
const_rtx cst = XEXP (cond, 1); rtx cst;
/* COND must be either an EQ or NE comparison. */
if (GET_CODE (cond) != EQ && GET_CODE (cond) != NE)
return false;
/* The first operand of COND must be a pseudo-reg. */
if (! REG_P (XEXP (cond, 0))
|| HARD_REGISTER_P (XEXP (cond, 0)))
return false;
/* The second operand of COND must be a suitable constant. */
mode = GET_MODE (XEXP (cond, 0));
cst = XEXP (cond, 1);
/* We can't perform this optimization if either operand might be or might /* We can't perform this optimization if either operand might be or might
contain a signed zero. */ contain a signed zero. */
...@@ -1382,55 +1395,78 @@ implicit_set_cond_p (const_rtx cond) ...@@ -1382,55 +1395,78 @@ implicit_set_cond_p (const_rtx cond)
function records the set patterns that are implicit at the start of each function records the set patterns that are implicit at the start of each
basic block. basic block.
FIXME: This would be more effective if critical edges are pre-split. As If an implicit set is found but the set is implicit on a critical edge,
it is now, we can't record implicit sets for blocks that have this critical edge is split.
critical successor edges. This results in missed optimizations
and in more (unnecessary) work in cfgcleanup.c:thread_jump(). */
static void Return true if the CFG was modified, false otherwise. */
static bool
find_implicit_sets (void) find_implicit_sets (void)
{ {
basic_block bb, dest; basic_block bb, dest;
unsigned int count;
rtx cond, new_rtx; rtx cond, new_rtx;
unsigned int count = 0;
bool edges_split = false;
size_t implicit_sets_size = last_basic_block + 10;
implicit_sets = XCNEWVEC (rtx, implicit_sets_size);
count = 0;
FOR_EACH_BB (bb) FOR_EACH_BB (bb)
/* Check for more than one successor. */ {
if (EDGE_COUNT (bb->succs) > 1) /* Check for more than one successor. */
{ if (! EDGE_COUNT (bb->succs) > 1)
cond = fis_get_condition (BB_END (bb)); continue;
if (cond cond = fis_get_condition (BB_END (bb));
&& (GET_CODE (cond) == EQ || GET_CODE (cond) == NE)
&& REG_P (XEXP (cond, 0))
&& REGNO (XEXP (cond, 0)) >= FIRST_PSEUDO_REGISTER
&& implicit_set_cond_p (cond))
{
dest = GET_CODE (cond) == EQ ? BRANCH_EDGE (bb)->dest
: FALLTHRU_EDGE (bb)->dest;
if (dest /* If no condition is found or if it isn't of a suitable form,
/* Record nothing for a critical edge. */ ignore it. */
&& single_pred_p (dest) if (! cond || ! implicit_set_cond_p (cond))
&& dest != EXIT_BLOCK_PTR) continue;
{
new_rtx = gen_rtx_SET (VOIDmode, XEXP (cond, 0), dest = GET_CODE (cond) == EQ
XEXP (cond, 1)); ? BRANCH_EDGE (bb)->dest : FALLTHRU_EDGE (bb)->dest;
implicit_sets[dest->index] = new_rtx;
if (dump_file) /* If DEST doesn't go anywhere, ignore it. */
{ if (! dest || dest == EXIT_BLOCK_PTR)
fprintf(dump_file, "Implicit set of reg %d in ", continue;
REGNO (XEXP (cond, 0)));
fprintf(dump_file, "basic block %d\n", dest->index); /* We have found a suitable implicit set. Try to record it now as
} a SET in DEST. If DEST has more than one predecessor, the edge
count++; between BB and DEST is a critical edge and we must split it,
} because we can only record one implicit set per DEST basic block. */
} if (! single_pred_p (dest))
{
dest = split_edge (find_edge (bb, dest));
edges_split = true;
}
if (implicit_sets_size <= (size_t) dest->index)
{
size_t old_implicit_sets_size = implicit_sets_size;
implicit_sets_size *= 2;
implicit_sets = XRESIZEVEC (rtx, implicit_sets, implicit_sets_size);
memset (implicit_sets + old_implicit_sets_size, 0,
(implicit_sets_size - old_implicit_sets_size) * sizeof (rtx));
} }
new_rtx = gen_rtx_SET (VOIDmode, XEXP (cond, 0),
XEXP (cond, 1));
implicit_sets[dest->index] = new_rtx;
if (dump_file)
{
fprintf(dump_file, "Implicit set of reg %d in ",
REGNO (XEXP (cond, 0)));
fprintf(dump_file, "basic block %d\n", dest->index);
}
count++;
}
if (dump_file) if (dump_file)
fprintf (dump_file, "Found %d implicit sets\n", count); fprintf (dump_file, "Found %d implicit sets\n", count);
/* Confess our sins. */
return edges_split;
} }
/* Bypass conditional jumps. */ /* Bypass conditional jumps. */
...@@ -1797,14 +1833,24 @@ one_cprop_pass (void) ...@@ -1797,14 +1833,24 @@ one_cprop_pass (void)
the solver implemented in this file. */ the solver implemented in this file. */
changed |= local_cprop_pass (); changed |= local_cprop_pass ();
if (changed) if (changed)
{ delete_unreachable_blocks ();
delete_unreachable_blocks ();
df_analyze (); /* Determine implicit sets. This may change the CFG (split critical
} edges if that exposes an implicit set).
Note that find_implicit_sets() does not rely on up-to-date DF caches
/* Determine implicit sets. */ so that we do not have to re-run df_analyze() even if local CPROP
implicit_sets = XCNEWVEC (rtx, last_basic_block); changed something.
find_implicit_sets (); ??? This could run earlier so that any uncovered implicit sets
sets could be exploited in local_cprop_pass() also. Later. */
changed |= find_implicit_sets ();
/* If local_cprop_pass() or find_implicit_sets() changed something,
run df_analyze() to bring all insn caches up-to-date, and to take
new basic blocks from edge splitting on the DF radar.
NB: This also runs the fast DCE pass, because execute_rtl_cprop
sets DF_LR_RUN_DCE. */
if (changed)
df_analyze ();
alloc_hash_table (&set_hash_table); alloc_hash_table (&set_hash_table);
compute_hash_table (&set_hash_table); compute_hash_table (&set_hash_table);
......
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