lambda-code.c (can_put_in_inner_loop): Relax restrictions.

2006-01-04  Daniel Berlin  <dberlin@dberlin.org>

	* lambda-code.c (can_put_in_inner_loop): Relax
	restrictions.
	(can_put_after_inner_loop): New function.
	(can_convert_to_perfect_nest): Use can_put_after_inner_loop as well.
	(perfect_nestify): Change to make copies and modify uses.

From-SVN: r109337
This commit is contained in:
Daniel Berlin 2006-01-04 16:34:52 +00:00 committed by Daniel Berlin
parent bc4071dd66
commit dc006c709d
2 changed files with 67 additions and 28 deletions

View File

@ -1,3 +1,11 @@
2006-01-04 Daniel Berlin <dberlin@dberlin.org>
* lambda-code.c (can_put_in_inner_loop): Relax
restrictions.
(can_put_after_inner_loop): New function.
(can_convert_to_perfect_nest): Use can_put_after_inner_loop as well.
(perfect_nestify): Change to make copies and modify uses.
2006-01-04 Richard Henderson <rth@redhat.com> 2006-01-04 Richard Henderson <rth@redhat.com>
Merge from gomp branch: Merge from gomp branch:

View File

@ -2201,23 +2201,20 @@ exit_phi_for_loop_p (struct loop *loop, tree stmt)
return true; return true;
} }
/* Return true if STMT can be put back into INNER, a loop by moving it to the /* Return true if STMT can be put back into the loop INNER, by
beginning of that loop. */ copying it to the beginning of that loop and changing the uses. */
static bool static bool
can_put_in_inner_loop (struct loop *inner, tree stmt) can_put_in_inner_loop (struct loop *inner, tree stmt)
{ {
imm_use_iterator imm_iter; imm_use_iterator imm_iter;
use_operand_p use_p; use_operand_p use_p;
basic_block use_bb = NULL;
gcc_assert (TREE_CODE (stmt) == MODIFY_EXPR); gcc_assert (TREE_CODE (stmt) == MODIFY_EXPR);
if (!ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS) if (!ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS)
|| !expr_invariant_in_loop_p (inner, TREE_OPERAND (stmt, 1))) || !expr_invariant_in_loop_p (inner, TREE_OPERAND (stmt, 1)))
return false; return false;
/* We require that the basic block of all uses be the same, or the use be an
exit phi. */
FOR_EACH_IMM_USE_FAST (use_p, imm_iter, TREE_OPERAND (stmt, 0)) FOR_EACH_IMM_USE_FAST (use_p, imm_iter, TREE_OPERAND (stmt, 0))
{ {
if (!exit_phi_for_loop_p (inner, USE_STMT (use_p))) if (!exit_phi_for_loop_p (inner, USE_STMT (use_p)))
@ -2226,17 +2223,39 @@ can_put_in_inner_loop (struct loop *inner, tree stmt)
if (!flow_bb_inside_loop_p (inner, immbb)) if (!flow_bb_inside_loop_p (inner, immbb))
return false; return false;
if (use_bb == NULL) }
use_bb = immbb; }
else if (immbb != use_bb) return true;
}
/* Return true if STMT can be put *after* the inner loop of LOOP. */
static bool
can_put_after_inner_loop (struct loop *loop, tree stmt)
{
imm_use_iterator imm_iter;
use_operand_p use_p;
if (!ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS))
return false;
FOR_EACH_IMM_USE_FAST (use_p, imm_iter, TREE_OPERAND (stmt, 0))
{
if (!exit_phi_for_loop_p (loop, USE_STMT (use_p)))
{
basic_block immbb = bb_for_stmt (USE_STMT (use_p));
if (!dominated_by_p (CDI_DOMINATORS,
immbb,
loop->inner->header)
&& !can_put_in_inner_loop (loop->inner, stmt))
return false; return false;
} }
} }
return true; return true;
} }
/* Return TRUE if LOOP is an imperfect nest that we can convert to a perfect /* Return TRUE if LOOP is an imperfect nest that we can convert to a perfect
one. LOOPIVS is a vector of induction variables, one per loop. one. LOOPIVS is a vector of induction variables, one per loop.
ATM, we only handle imperfect nests of depth 2, where all of the statements ATM, we only handle imperfect nests of depth 2, where all of the statements
@ -2277,18 +2296,20 @@ can_convert_to_perfect_nest (struct loop *loop,
if (stmt_uses_op (stmt, iv)) if (stmt_uses_op (stmt, iv))
goto fail; goto fail;
/* If this is a simple operation like a cast that is invariant /* If this is a simple operation like a cast that is
in the inner loop, only used there, and we can place it invariant in the inner loop, or after the inner loop,
there, then it's not going to hurt us. then see if we can place it back where it came from.
This means that we will propagate casts and other cheap This means that we will propagate casts and other
invariant operations *back* cheap invariant operations *back* into or after
into the inner loop if we can interchange the loop, on the the inner loop if we can interchange the loop, on the
theory that we are going to gain a lot more by interchanging theory that we are going to gain a lot more by
the loop than we are by leaving some invariant code there for interchanging the loop than we are by leaving some
some other pass to clean up. */ invariant code there for some other pass to clean
up. */
if (TREE_CODE (stmt) == MODIFY_EXPR if (TREE_CODE (stmt) == MODIFY_EXPR
&& is_gimple_cast (TREE_OPERAND (stmt, 1)) && is_gimple_cast (TREE_OPERAND (stmt, 1))
&& can_put_in_inner_loop (loop->inner, stmt)) && (can_put_in_inner_loop (loop->inner, stmt)
|| can_put_after_inner_loop (loop, stmt)))
continue; continue;
/* Otherwise, if the bb of a statement we care about isn't /* Otherwise, if the bb of a statement we care about isn't
@ -2515,23 +2536,33 @@ perfect_nestify (struct loops *loops,
bsi_prev (&bsi); bsi_prev (&bsi);
continue; continue;
} }
/* Move this statement back into the inner loop.
This looks a bit confusing, but we are really just /* Make copies of this statement to put it back next
finding the first non-exit phi use and moving the to its uses. */
statement to the beginning of that use's basic
block. */
FOR_EACH_IMM_USE_SAFE (use_p, imm_iter, FOR_EACH_IMM_USE_SAFE (use_p, imm_iter,
TREE_OPERAND (stmt, 0)) TREE_OPERAND (stmt, 0))
{ {
tree imm_stmt = USE_STMT (use_p); tree imm_stmt = USE_STMT (use_p);
if (!exit_phi_for_loop_p (loop->inner, imm_stmt)) if (!exit_phi_for_loop_p (loop->inner, imm_stmt))
{ {
block_stmt_iterator tobsi = bsi_after_labels (bb_for_stmt (imm_stmt)); block_stmt_iterator tobsi;
bsi_move_after (&bsi, &tobsi); tree newname;
update_stmt (stmt); tree newstmt;
BREAK_FROM_SAFE_IMM_USE (imm_iter);
newstmt = unshare_expr (stmt);
tobsi = bsi_after_labels (bb_for_stmt (imm_stmt));
newname = TREE_OPERAND (newstmt, 0);
newname = SSA_NAME_VAR (newname);
newname = make_ssa_name (newname, newstmt);
TREE_OPERAND (newstmt, 0) = newname;
SET_USE (use_p, TREE_OPERAND (newstmt, 0));
bsi_insert_after (&tobsi, newstmt, BSI_SAME_STMT);
update_stmt (newstmt);
update_stmt (imm_stmt);
} }
} }
if (!bsi_end_p (bsi))
bsi_prev (&bsi);
} }
} }
else else