Commit d4fdb4df by Jeff Law Committed by Jeff Law

tree-ssa-threadedge.c (record_temporary_equivalence): Handle NULL for RHS, which…

tree-ssa-threadedge.c (record_temporary_equivalence): Handle NULL for RHS, which we used to invalidate equivalences.

	* tree-ssa-threadedge.c (record_temporary_equivalence): Handle
	NULL for RHS, which we used to invalidate equivalences.
	(record_temporary_equivalences_from_phis): New bitmap arguments
	and a boolean indicating if we have passed a backedge.  If we
	have passed a backedge, then set the appropriate bit in the
	bitmaps for the SRC & DEST of PHIs creating equivalences.
	(invalidate_equivalences, dummy_simplify): New functions.
	(cond_arg_set_in_b): Remove.
	(record_temporary_equivalences_from_stmts_at_dest): New bitmap
	arguments and a boolean indicating if we have passed a backedge.
	If we have passed a backedge, then perform invalidations as
	needed.
	(thread_around_empty_blocks): If we have seen a backedge, then
	use the dummy simplify routine.
	(thread_through_normal_block): Likewise.  Pass bitmaps and
	backedge status to children.  Do not pessimize so much when
	traversing backedges in the CFG.
	(thread_across_edge): Manage the SRC_MAP/DST_MAP bitmaps.
	If we have seen a backedge, then use the dummy simplify routine.
	Do not pessimize so much when traversing backedges.

From-SVN: r205279
parent 7d20ca61
2013-11-22 Jeff Law <law@redhat.com>
* tree-ssa-threadedge.c (record_temporary_equivalence): Handle
NULL for RHS, which we used to invalidate equivalences.
(record_temporary_equivalences_from_phis): New bitmap arguments
and a boolean indicating if we have passed a backedge. If we
have passed a backedge, then set the appropriate bit in the
bitmaps for the SRC & DEST of PHIs creating equivalences.
(invalidate_equivalences, dummy_simplify): New functions.
(cond_arg_set_in_b): Remove.
(record_temporary_equivalences_from_stmts_at_dest): New bitmap
arguments and a boolean indicating if we have passed a backedge.
If we have passed a backedge, then perform invalidations as
needed.
(thread_around_empty_blocks): If we have seen a backedge, then
use the dummy simplify routine.
(thread_through_normal_block): Likewise. Pass bitmaps and
backedge status to children. Do not pessimize so much when
traversing backedges in the CFG.
(thread_across_edge): Manage the SRC_MAP/DST_MAP bitmaps.
If we have seen a backedge, then use the dummy simplify routine.
Do not pessimize so much when traversing backedges.
2013-11-22 Hans-Peter Nilsson <hp@axis.com> 2013-11-22 Hans-Peter Nilsson <hp@axis.com>
* config/cris/cris.c (cris_atomic_align_for_mode): New function. * config/cris/cris.c (cris_atomic_align_for_mode): New function.
...@@ -175,7 +175,8 @@ record_temporary_equivalence (tree x, tree y, vec<tree> *stack) ...@@ -175,7 +175,8 @@ record_temporary_equivalence (tree x, tree y, vec<tree> *stack)
{ {
tree prev_x = SSA_NAME_VALUE (x); tree prev_x = SSA_NAME_VALUE (x);
if (TREE_CODE (y) == SSA_NAME) /* Y may be NULL if we are invalidating entries in the table. */
if (y && TREE_CODE (y) == SSA_NAME)
{ {
tree tmp = SSA_NAME_VALUE (y); tree tmp = SSA_NAME_VALUE (y);
y = tmp ? tmp : y; y = tmp ? tmp : y;
...@@ -191,10 +192,16 @@ record_temporary_equivalence (tree x, tree y, vec<tree> *stack) ...@@ -191,10 +192,16 @@ record_temporary_equivalence (tree x, tree y, vec<tree> *stack)
edge E. Record unwind information for the equivalences onto STACK. edge E. Record unwind information for the equivalences onto STACK.
If a PHI which prevents threading is encountered, then return FALSE If a PHI which prevents threading is encountered, then return FALSE
indicating we should not thread this edge, else return TRUE. */ indicating we should not thread this edge, else return TRUE.
If SRC_MAP/DST_MAP exist, then mark the source and destination SSA_NAMEs
of any equivalences recorded. We use this to make invalidation after
traversing back edges less painful. */
static bool static bool
record_temporary_equivalences_from_phis (edge e, vec<tree> *stack) record_temporary_equivalences_from_phis (edge e, vec<tree> *stack,
bool backedge_seen,
bitmap src_map, bitmap dst_map)
{ {
gimple_stmt_iterator gsi; gimple_stmt_iterator gsi;
...@@ -222,6 +229,14 @@ record_temporary_equivalences_from_phis (edge e, vec<tree> *stack) ...@@ -222,6 +229,14 @@ record_temporary_equivalences_from_phis (edge e, vec<tree> *stack)
stmt_count++; stmt_count++;
record_temporary_equivalence (dst, src, stack); record_temporary_equivalence (dst, src, stack);
/* If we have crossed a backedge, then start recording equivalences
we might need to invalidate. */
if (backedge_seen && TREE_CODE (src) == SSA_NAME)
{
bitmap_set_bit (src_map, SSA_NAME_VERSION (src));
bitmap_set_bit (dst_map, SSA_NAME_VERSION (dst));
}
} }
return true; return true;
} }
...@@ -276,6 +291,34 @@ fold_assignment_stmt (gimple stmt) ...@@ -276,6 +291,34 @@ fold_assignment_stmt (gimple stmt)
} }
} }
/* A new value has been assigned to LHS. If necessary, invalidate any
equivalences that are no longer valid. */
static void
invalidate_equivalences (tree lhs, vec<tree> *stack,
bitmap src_map, bitmap dst_map)
{
/* SRC_MAP contains the source SSA_NAMEs for equivalences created by PHI
nodes. If an entry in SRC_MAP changes, there's some destination that
has been recorded as equivalent to the source and that equivalency
needs to be eliminated. */
if (bitmap_bit_p (src_map, SSA_NAME_VERSION (lhs)))
{
unsigned int i;
bitmap_iterator bi;
/* We know that the LHS of STMT was used as the RHS in an equivalency
created by a PHI. All the LHS of such PHIs were recorded into DST_MAP.
So we can iterate over them to see if any have the LHS of STMT as
an equivalence, and if so, remove the equivalence as it is no longer
valid. */
EXECUTE_IF_SET_IN_BITMAP (dst_map, 0, i, bi)
{
if (SSA_NAME_VALUE (ssa_name (i)) == lhs)
record_temporary_equivalence (ssa_name (i), NULL_TREE, stack);
}
}
}
/* Try to simplify each statement in E->dest, ultimately leading to /* Try to simplify each statement in E->dest, ultimately leading to
a simplification of the COND_EXPR at the end of E->dest. a simplification of the COND_EXPR at the end of E->dest.
...@@ -297,7 +340,10 @@ static gimple ...@@ -297,7 +340,10 @@ static gimple
record_temporary_equivalences_from_stmts_at_dest (edge e, record_temporary_equivalences_from_stmts_at_dest (edge e,
vec<tree> *stack, vec<tree> *stack,
tree (*simplify) (gimple, tree (*simplify) (gimple,
gimple)) gimple),
bool backedge_seen,
bitmap src_map,
bitmap dst_map)
{ {
gimple stmt = NULL; gimple stmt = NULL;
gimple_stmt_iterator gsi; gimple_stmt_iterator gsi;
...@@ -374,7 +420,15 @@ record_temporary_equivalences_from_stmts_at_dest (edge e, ...@@ -374,7 +420,15 @@ record_temporary_equivalences_from_stmts_at_dest (edge e,
if (fndecl if (fndecl
&& (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_OBJECT_SIZE && (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_OBJECT_SIZE
|| DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CONSTANT_P)) || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CONSTANT_P))
continue; {
if (backedge_seen)
{
tree lhs = gimple_get_lhs (stmt);
record_temporary_equivalence (lhs, NULL_TREE, stack);
invalidate_equivalences (lhs, stack, src_map, dst_map);
}
continue;
}
} }
/* At this point we have a statement which assigns an RHS to an /* At this point we have a statement which assigns an RHS to an
...@@ -438,15 +492,36 @@ record_temporary_equivalences_from_stmts_at_dest (edge e, ...@@ -438,15 +492,36 @@ record_temporary_equivalences_from_stmts_at_dest (edge e,
} }
/* Record the context sensitive equivalence if we were able /* Record the context sensitive equivalence if we were able
to simplify this statement. */ to simplify this statement.
If we have traversed a backedge at some point during threading,
then always enter something here. Either a real equivalence,
or a NULL_TREE equivalence which is effectively invalidation of
prior equivalences. */
if (cached_lhs if (cached_lhs
&& (TREE_CODE (cached_lhs) == SSA_NAME && (TREE_CODE (cached_lhs) == SSA_NAME
|| is_gimple_min_invariant (cached_lhs))) || is_gimple_min_invariant (cached_lhs)))
record_temporary_equivalence (gimple_get_lhs (stmt), cached_lhs, stack); record_temporary_equivalence (gimple_get_lhs (stmt), cached_lhs, stack);
else if (backedge_seen)
record_temporary_equivalence (gimple_get_lhs (stmt), NULL_TREE, stack);
if (backedge_seen)
invalidate_equivalences (gimple_get_lhs (stmt), stack,
src_map, dst_map);
} }
return stmt; return stmt;
} }
/* Once we have passed a backedge in the CFG when threading, we do not want to
utilize edge equivalences for simplification purpose. They are no longer
necessarily valid. We use this callback rather than the ones provided by
DOM/VRP to achieve that effect. */
static tree
dummy_simplify (gimple stmt1 ATTRIBUTE_UNUSED, gimple stmt2 ATTRIBUTE_UNUSED)
{
return NULL_TREE;
}
/* Simplify the control statement at the end of the block E->dest. /* Simplify the control statement at the end of the block E->dest.
To avoid allocating memory unnecessarily, a scratch GIMPLE_COND To avoid allocating memory unnecessarily, a scratch GIMPLE_COND
...@@ -586,44 +661,6 @@ simplify_control_stmt_condition (edge e, ...@@ -586,44 +661,6 @@ simplify_control_stmt_condition (edge e,
return cached_lhs; return cached_lhs;
} }
/* Return TRUE if the statement at the end of e->dest depends on
the output of any statement in BB. Otherwise return FALSE.
This is used when we are threading a backedge and need to ensure
that temporary equivalences from BB do not affect the condition
in e->dest. */
static bool
cond_arg_set_in_bb (edge e, basic_block bb)
{
ssa_op_iter iter;
use_operand_p use_p;
gimple last = last_stmt (e->dest);
/* E->dest does not have to end with a control transferring
instruction. This can occur when we try to extend a jump
threading opportunity deeper into the CFG. In that case
it is safe for this check to return false. */
if (!last)
return false;
if (gimple_code (last) != GIMPLE_COND
&& gimple_code (last) != GIMPLE_GOTO
&& gimple_code (last) != GIMPLE_SWITCH)
return false;
FOR_EACH_SSA_USE_OPERAND (use_p, last, iter, SSA_OP_USE | SSA_OP_VUSE)
{
tree use = USE_FROM_PTR (use_p);
if (TREE_CODE (use) == SSA_NAME
&& gimple_code (SSA_NAME_DEF_STMT (use)) != GIMPLE_PHI
&& gimple_bb (SSA_NAME_DEF_STMT (use)) == bb)
return true;
}
return false;
}
/* Copy debug stmts from DEST's chain of single predecessors up to /* Copy debug stmts from DEST's chain of single predecessors up to
SRC, so that we don't lose the bindings as PHI nodes are introduced SRC, so that we don't lose the bindings as PHI nodes are introduced
when DEST gains new predecessors. */ when DEST gains new predecessors. */
...@@ -810,6 +847,8 @@ thread_around_empty_blocks (edge taken_edge, ...@@ -810,6 +847,8 @@ thread_around_empty_blocks (edge taken_edge,
path->safe_push (x); path->safe_push (x);
bitmap_set_bit (visited, taken_edge->dest->index); bitmap_set_bit (visited, taken_edge->dest->index);
*backedge_seen_p |= ((taken_edge->flags & EDGE_DFS_BACK) != 0); *backedge_seen_p |= ((taken_edge->flags & EDGE_DFS_BACK) != 0);
if (*backedge_seen_p)
simplify = dummy_simplify;
return thread_around_empty_blocks (taken_edge, return thread_around_empty_blocks (taken_edge,
dummy_cond, dummy_cond,
handle_dominating_asserts, handle_dominating_asserts,
...@@ -832,6 +871,13 @@ thread_around_empty_blocks (edge taken_edge, ...@@ -832,6 +871,13 @@ thread_around_empty_blocks (edge taken_edge,
&& gimple_code (stmt) != GIMPLE_SWITCH) && gimple_code (stmt) != GIMPLE_SWITCH)
return false; return false;
/* If we have traversed a backedge, then we do not want to look
at certain expressions in the table that can not be relied upon.
Luckily the only code that looked at those expressions is the
SIMPLIFY callback, which we replace if we can no longer use it. */
if (*backedge_seen_p)
simplify = dummy_simplify;
/* Extract and simplify the condition. */ /* Extract and simplify the condition. */
cond = simplify_control_stmt_condition (taken_edge, stmt, dummy_cond, cond = simplify_control_stmt_condition (taken_edge, stmt, dummy_cond,
simplify, handle_dominating_asserts); simplify, handle_dominating_asserts);
...@@ -851,6 +897,8 @@ thread_around_empty_blocks (edge taken_edge, ...@@ -851,6 +897,8 @@ thread_around_empty_blocks (edge taken_edge,
= new jump_thread_edge (taken_edge, EDGE_NO_COPY_SRC_BLOCK); = new jump_thread_edge (taken_edge, EDGE_NO_COPY_SRC_BLOCK);
path->safe_push (x); path->safe_push (x);
*backedge_seen_p |= ((taken_edge->flags & EDGE_DFS_BACK) != 0); *backedge_seen_p |= ((taken_edge->flags & EDGE_DFS_BACK) != 0);
if (*backedge_seen_p)
simplify = dummy_simplify;
thread_around_empty_blocks (taken_edge, thread_around_empty_blocks (taken_edge,
dummy_cond, dummy_cond,
...@@ -901,24 +949,28 @@ thread_through_normal_block (edge e, ...@@ -901,24 +949,28 @@ thread_through_normal_block (edge e,
tree (*simplify) (gimple, gimple), tree (*simplify) (gimple, gimple),
vec<jump_thread_edge *> *path, vec<jump_thread_edge *> *path,
bitmap visited, bitmap visited,
bool *backedge_seen_p) bool *backedge_seen_p,
bitmap src_map,
bitmap dst_map)
{ {
/* If we have crossed a backedge, then we want to verify that the COND_EXPR, /* If we have traversed a backedge, then we do not want to look
SWITCH_EXPR or GOTO_EXPR at the end of e->dest is not affected at certain expressions in the table that can not be relied upon.
by any statements in e->dest. If it is affected, then it is not Luckily the only code that looked at those expressions is the
safe to thread this edge. */ SIMPLIFY callback, which we replace if we can no longer use it. */
if (*backedge_seen_p if (*backedge_seen_p)
&& cond_arg_set_in_bb (e, e->dest)) simplify = dummy_simplify;
return false;
/* PHIs create temporary equivalences. */ /* PHIs create temporary equivalences. */
if (!record_temporary_equivalences_from_phis (e, stack)) if (!record_temporary_equivalences_from_phis (e, stack, *backedge_seen_p,
src_map, dst_map))
return false; return false;
/* Now walk each statement recording any context sensitive /* Now walk each statement recording any context sensitive
temporary equivalences we can detect. */ temporary equivalences we can detect. */
gimple stmt gimple stmt
= record_temporary_equivalences_from_stmts_at_dest (e, stack, simplify); = record_temporary_equivalences_from_stmts_at_dest (e, stack, simplify,
*backedge_seen_p,
src_map, dst_map);
if (!stmt) if (!stmt)
return false; return false;
...@@ -960,25 +1012,24 @@ thread_through_normal_block (edge e, ...@@ -960,25 +1012,24 @@ thread_through_normal_block (edge e,
= new jump_thread_edge (taken_edge, EDGE_COPY_SRC_BLOCK); = new jump_thread_edge (taken_edge, EDGE_COPY_SRC_BLOCK);
path->safe_push (x); path->safe_push (x);
*backedge_seen_p |= ((taken_edge->flags & EDGE_DFS_BACK) != 0); *backedge_seen_p |= ((taken_edge->flags & EDGE_DFS_BACK) != 0);
if (*backedge_seen_p)
simplify = dummy_simplify;
/* See if we can thread through DEST as well, this helps capture /* See if we can thread through DEST as well, this helps capture
secondary effects of threading without having to re-run DOM or secondary effects of threading without having to re-run DOM or
VRP. */ VRP.
if (!*backedge_seen_p
|| ! cond_arg_set_in_bb (taken_edge, e->dest)) We don't want to thread back to a block we have already
{ visited. This may be overly conservative. */
/* We don't want to thread back to a block we have already bitmap_set_bit (visited, dest->index);
visited. This may be overly conservative. */ bitmap_set_bit (visited, e->dest->index);
bitmap_set_bit (visited, dest->index); thread_around_empty_blocks (taken_edge,
bitmap_set_bit (visited, e->dest->index); dummy_cond,
thread_around_empty_blocks (taken_edge, handle_dominating_asserts,
dummy_cond, simplify,
handle_dominating_asserts, visited,
simplify, path,
visited, backedge_seen_p);
path,
backedge_seen_p);
}
return true; return true;
} }
} }
...@@ -1020,6 +1071,8 @@ thread_across_edge (gimple dummy_cond, ...@@ -1020,6 +1071,8 @@ thread_across_edge (gimple dummy_cond,
tree (*simplify) (gimple, gimple)) tree (*simplify) (gimple, gimple))
{ {
bitmap visited = BITMAP_ALLOC (NULL); bitmap visited = BITMAP_ALLOC (NULL);
bitmap src_map = BITMAP_ALLOC (NULL);
bitmap dst_map = BITMAP_ALLOC (NULL);
bool backedge_seen; bool backedge_seen;
stmt_count = 0; stmt_count = 0;
...@@ -1029,14 +1082,19 @@ thread_across_edge (gimple dummy_cond, ...@@ -1029,14 +1082,19 @@ thread_across_edge (gimple dummy_cond,
bitmap_set_bit (visited, e->src->index); bitmap_set_bit (visited, e->src->index);
bitmap_set_bit (visited, e->dest->index); bitmap_set_bit (visited, e->dest->index);
backedge_seen = ((e->flags & EDGE_DFS_BACK) != 0); backedge_seen = ((e->flags & EDGE_DFS_BACK) != 0);
if (backedge_seen)
simplify = dummy_simplify;
if (thread_through_normal_block (e, dummy_cond, handle_dominating_asserts, if (thread_through_normal_block (e, dummy_cond, handle_dominating_asserts,
stack, simplify, path, visited, stack, simplify, path, visited,
&backedge_seen)) &backedge_seen, src_map, dst_map))
{ {
propagate_threaded_block_debug_into (path->last ()->e->dest, propagate_threaded_block_debug_into (path->last ()->e->dest,
e->dest); e->dest);
remove_temporary_equivalences (stack); remove_temporary_equivalences (stack);
BITMAP_FREE (visited); BITMAP_FREE (visited);
BITMAP_FREE (src_map);
BITMAP_FREE (dst_map);
register_jump_thread (path); register_jump_thread (path);
return; return;
} }
...@@ -1071,15 +1129,26 @@ thread_across_edge (gimple dummy_cond, ...@@ -1071,15 +1129,26 @@ thread_across_edge (gimple dummy_cond,
{ {
remove_temporary_equivalences (stack); remove_temporary_equivalences (stack);
BITMAP_FREE (visited); BITMAP_FREE (visited);
BITMAP_FREE (src_map);
BITMAP_FREE (dst_map);
return; return;
} }
/* We need to restore the state of the maps to this point each loop
iteration. */
bitmap src_map_copy = BITMAP_ALLOC (NULL);
bitmap dst_map_copy = BITMAP_ALLOC (NULL);
bitmap_copy (src_map_copy, src_map);
bitmap_copy (dst_map_copy, dst_map);
/* Look at each successor of E->dest to see if we can thread through it. */ /* Look at each successor of E->dest to see if we can thread through it. */
FOR_EACH_EDGE (taken_edge, ei, e->dest->succs) FOR_EACH_EDGE (taken_edge, ei, e->dest->succs)
{ {
/* Push a fresh marker so we can unwind the equivalences created /* Push a fresh marker so we can unwind the equivalences created
for each of E->dest's successors. */ for each of E->dest's successors. */
stack->safe_push (NULL_TREE); stack->safe_push (NULL_TREE);
bitmap_copy (src_map, src_map_copy);
bitmap_copy (dst_map, dst_map_copy);
/* Avoid threading to any block we have already visited. */ /* Avoid threading to any block we have already visited. */
bitmap_clear (visited); bitmap_clear (visited);
...@@ -1098,23 +1167,25 @@ thread_across_edge (gimple dummy_cond, ...@@ -1098,23 +1167,25 @@ thread_across_edge (gimple dummy_cond,
found = false; found = false;
backedge_seen = ((e->flags & EDGE_DFS_BACK) != 0); backedge_seen = ((e->flags & EDGE_DFS_BACK) != 0);
backedge_seen |= ((taken_edge->flags & EDGE_DFS_BACK) != 0); backedge_seen |= ((taken_edge->flags & EDGE_DFS_BACK) != 0);
if (!backedge_seen if (backedge_seen)
|| ! cond_arg_set_in_bb (path->last ()->e, e->dest)) simplify = dummy_simplify;
found = thread_around_empty_blocks (taken_edge, found = thread_around_empty_blocks (taken_edge,
dummy_cond, dummy_cond,
handle_dominating_asserts, handle_dominating_asserts,
simplify, simplify,
visited, visited,
path, path,
&backedge_seen); &backedge_seen);
if (!found if (backedge_seen)
&& (!backedge_seen simplify = dummy_simplify;
|| ! cond_arg_set_in_bb (path->last ()->e, e->dest)))
if (!found)
found = thread_through_normal_block (path->last ()->e, dummy_cond, found = thread_through_normal_block (path->last ()->e, dummy_cond,
handle_dominating_asserts, handle_dominating_asserts,
stack, simplify, path, visited, stack, simplify, path, visited,
&backedge_seen); &backedge_seen,
src_map, dst_map);
/* If we were able to thread through a successor of E->dest, then /* If we were able to thread through a successor of E->dest, then
record the jump threading opportunity. */ record the jump threading opportunity. */
...@@ -1133,6 +1204,10 @@ thread_across_edge (gimple dummy_cond, ...@@ -1133,6 +1204,10 @@ thread_across_edge (gimple dummy_cond,
remove_temporary_equivalences (stack); remove_temporary_equivalences (stack);
} }
BITMAP_FREE (visited); BITMAP_FREE (visited);
BITMAP_FREE (src_map);
BITMAP_FREE (dst_map);
BITMAP_FREE (src_map_copy);
BITMAP_FREE (dst_map_copy);
} }
remove_temporary_equivalences (stack); remove_temporary_equivalences (stack);
......
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