Commit 64e13bcd by Jeff Law Committed by Jeff Law

re PR tree-optimization/61289 (Bad jump threading generates infinite loop)

	PR tree-optimization/61289
	* tree-ssa-threadedge.c (invalidate_equivalences): Remove SRC_MAP and
	DST_MAP parameters.   Invalidate by walking all the SSA_NAME_VALUES
	looking for those which match LHS.  All callers changed.
	(record_temporary_equivalences_from_phis): Remove SRC_MAP and DST_MAP
	parameters and code which manipulated them.  All callers changed.
	(record_temporary_equivalences_from_stmts_at_dest): Remove SRC_MAP
	and DST_MAP parameters.  Simplify invalidation code by just calling
	invalidate_equivalences.  All callers changed.
	(thread_across_edge): Simplify now that we don't need to maintain
	the map of equivalences to invalidate.

        PR tree-optimization/61289
	* g++.dg/pr61289.C: New test.
	* g++.dg/pr61289-2.C: New test.

From-SVN: r211287
parent 406d3663
2014-06-05 Jeff Law <law@redhat.com>
PR tree-optimization/61289
* tree-ssa-threadedge.c (invalidate_equivalences): Remove SRC_MAP and
DST_MAP parameters. Invalidate by walking all the SSA_NAME_VALUES
looking for those which match LHS. All callers changed.
(record_temporary_equivalences_from_phis): Remove SRC_MAP and DST_MAP
parameters and code which manipulated them. All callers changed.
(record_temporary_equivalences_from_stmts_at_dest): Remove SRC_MAP
and DST_MAP parameters. Simplify invalidation code by just calling
invalidate_equivalences. All callers changed.
(thread_across_edge): Simplify now that we don't need to maintain
the map of equivalences to invalidate.
2014-06-05 Kai Tietz <ktietz@redhat.com> 2014-06-05 Kai Tietz <ktietz@redhat.com>
Richard Henderson <rth@redhat.com> Richard Henderson <rth@redhat.com>
......
2014-06-05 Jeff Law <law@redhat.com>
PR tree-optimization/61289
* g++.dg/pr61289.C: New test.
* g++.dg/pr61289-2.C: New test.
2014-06-05 Richard Biener <rguenther@suse.de> 2014-06-05 Richard Biener <rguenther@suse.de>
Paolo Carlini <paolo.carlini@oracle.com> Paolo Carlini <paolo.carlini@oracle.com>
......
/* { dg-do run } */
/* { dg-options "-O2 -fno-exceptions" } */
struct S
{
inline int fn1 () const { return s; }
__attribute__ ((noinline, noclone)) S *fn2 (int);
__attribute__ ((noinline, noclone)) void fn3 ();
__attribute__ ((noinline, noclone)) static S *fn4 (int);
S (int i) : s (i) {}
int s;
};
int a = 0;
S *b = 0;
S *
S::fn2 (int i)
{
a++;
if (a == 1)
return b;
if (a > 3)
__builtin_abort ();
b = this;
return new S (i + s);
}
S *
S::fn4 (int i)
{
b = new S (i);
return b;
}
void
S::fn3 ()
{
delete this;
}
void
foo ()
{
S *c = S::fn4 (20);
for (int i = 0; i < 2;)
{
S *d = c->fn2 (c->fn1 () + 10);
if (c != d)
{
c->fn3 ();
c = d;
++i;
}
}
c->fn3 ();
}
int
main ()
{
foo ();
}
/* { dg-do run } */
/* { dg-options "-O2 -fno-exceptions" } */
struct S
{
inline int fn1 () const { return s; }
__attribute__ ((noinline, noclone)) S *fn2 (int);
__attribute__ ((noinline, noclone)) void fn3 ();
__attribute__ ((noinline, noclone)) static S *fn4 (int);
S (int i) : s (i) {}
int s;
};
int a = 0;
S *b = 0;
S *
S::fn2 (int i)
{
a++;
if (a == 1)
return b;
if (a > 3)
__builtin_abort ();
b = this;
return new S (i + s);
}
S *
S::fn4 (int i)
{
b = new S (i);
return b;
}
void
S::fn3 ()
{
delete this;
}
void
foo ()
{
S *c = S::fn4 (20);
for (int i = 0; i < 2;)
{
S *d = c->fn2 (c->fn1 () + 10);
if (d != c)
{
c->fn3 ();
c = d;
++i;
}
}
c->fn3 ();
}
int
main ()
{
foo ();
}
...@@ -200,9 +200,7 @@ record_temporary_equivalence (tree x, tree y, vec<tree> *stack) ...@@ -200,9 +200,7 @@ record_temporary_equivalence (tree x, tree y, vec<tree> *stack)
traversing back edges less painful. */ 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;
...@@ -230,14 +228,6 @@ record_temporary_equivalences_from_phis (edge e, vec<tree> *stack, ...@@ -230,14 +228,6 @@ 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;
} }
...@@ -295,29 +285,15 @@ fold_assignment_stmt (gimple stmt) ...@@ -295,29 +285,15 @@ fold_assignment_stmt (gimple stmt)
/* A new value has been assigned to LHS. If necessary, invalidate any /* A new value has been assigned to LHS. If necessary, invalidate any
equivalences that are no longer valid. */ equivalences that are no longer valid. */
static void static void
invalidate_equivalences (tree lhs, vec<tree> *stack, 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 for (unsigned int i = 1; i < num_ssa_names; i++)
has been recorded as equivalent to the source and that equivalency if (ssa_name (i) && SSA_NAME_VALUE (ssa_name (i)) == lhs)
needs to be eliminated. */ record_temporary_equivalence (ssa_name (i), NULL_TREE, stack);
if (bitmap_bit_p (src_map, SSA_NAME_VERSION (lhs)))
{ if (SSA_NAME_VALUE (lhs))
unsigned int i; record_temporary_equivalence (lhs, NULL_TREE, stack);
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
...@@ -342,9 +318,7 @@ record_temporary_equivalences_from_stmts_at_dest (edge e, ...@@ -342,9 +318,7 @@ 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, bool backedge_seen)
bitmap src_map,
bitmap dst_map)
{ {
gimple stmt = NULL; gimple stmt = NULL;
gimple_stmt_iterator gsi; gimple_stmt_iterator gsi;
...@@ -400,19 +374,7 @@ record_temporary_equivalences_from_stmts_at_dest (edge e, ...@@ -400,19 +374,7 @@ record_temporary_equivalences_from_stmts_at_dest (edge e,
if (backedge_seen) if (backedge_seen)
FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_DEF) FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_DEF)
{ invalidate_equivalences (op, stack);
/* This call only invalidates equivalences created by
PHI nodes. This is by design to keep the cost of
of invalidation reasonable. */
invalidate_equivalences (op, stack, src_map, dst_map);
/* However, conditionals can imply values for real
operands as well. And those won't be recorded in the
maps. In fact, those equivalences may be recorded totally
outside the threading code. We can just create a new
temporary NULL equivalence here. */
record_temporary_equivalence (op, NULL_TREE, stack);
}
continue; continue;
} }
...@@ -452,8 +414,7 @@ record_temporary_equivalences_from_stmts_at_dest (edge e, ...@@ -452,8 +414,7 @@ record_temporary_equivalences_from_stmts_at_dest (edge e,
if (backedge_seen) if (backedge_seen)
{ {
tree lhs = gimple_get_lhs (stmt); tree lhs = gimple_get_lhs (stmt);
record_temporary_equivalence (lhs, NULL_TREE, stack); invalidate_equivalences (lhs, stack);
invalidate_equivalences (lhs, stack, src_map, dst_map);
} }
continue; continue;
} }
...@@ -531,11 +492,7 @@ record_temporary_equivalences_from_stmts_at_dest (edge e, ...@@ -531,11 +492,7 @@ record_temporary_equivalences_from_stmts_at_dest (edge e,
|| 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) else if (backedge_seen)
record_temporary_equivalence (gimple_get_lhs (stmt), NULL_TREE, stack); invalidate_equivalences (gimple_get_lhs (stmt), stack);
if (backedge_seen)
invalidate_equivalences (gimple_get_lhs (stmt), stack,
src_map, dst_map);
} }
return stmt; return stmt;
} }
...@@ -982,9 +939,7 @@ thread_through_normal_block (edge e, ...@@ -982,9 +939,7 @@ 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 traversed a backedge, then we do not want to look /* 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. at certain expressions in the table that can not be relied upon.
...@@ -994,16 +949,14 @@ thread_through_normal_block (edge e, ...@@ -994,16 +949,14 @@ thread_through_normal_block (edge e,
simplify = dummy_simplify; simplify = dummy_simplify;
/* PHIs create temporary equivalences. */ /* PHIs create temporary equivalences. */
if (!record_temporary_equivalences_from_phis (e, stack, *backedge_seen_p, if (!record_temporary_equivalences_from_phis (e, stack))
src_map, dst_map))
return 0; return 0;
/* 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, *backedge_seen_p);
src_map, dst_map);
/* If we didn't look at all the statements, the most likely reason is /* If we didn't look at all the statements, the most likely reason is
there were too many and thus duplicating this block is not profitable. there were too many and thus duplicating this block is not profitable.
...@@ -1112,8 +1065,6 @@ thread_across_edge (gimple dummy_cond, ...@@ -1112,8 +1065,6 @@ 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;
...@@ -1129,16 +1080,13 @@ thread_across_edge (gimple dummy_cond, ...@@ -1129,16 +1080,13 @@ thread_across_edge (gimple dummy_cond,
int threaded = thread_through_normal_block (e, dummy_cond, int threaded = thread_through_normal_block (e, dummy_cond,
handle_dominating_asserts, handle_dominating_asserts,
stack, simplify, path, stack, simplify, path,
visited, &backedge_seen, visited, &backedge_seen);
src_map, dst_map);
if (threaded > 0) if (threaded > 0)
{ {
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;
} }
...@@ -1160,8 +1108,6 @@ thread_across_edge (gimple dummy_cond, ...@@ -1160,8 +1108,6 @@ thread_across_edge (gimple dummy_cond,
if (threaded < 0) if (threaded < 0)
{ {
BITMAP_FREE (visited); BITMAP_FREE (visited);
BITMAP_FREE (src_map);
BITMAP_FREE (dst_map);
remove_temporary_equivalences (stack); remove_temporary_equivalences (stack);
return; return;
} }
...@@ -1190,26 +1136,15 @@ thread_across_edge (gimple dummy_cond, ...@@ -1190,26 +1136,15 @@ 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);
...@@ -1245,8 +1180,7 @@ thread_across_edge (gimple dummy_cond, ...@@ -1245,8 +1180,7 @@ thread_across_edge (gimple dummy_cond,
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) > 0;
src_map, dst_map) > 0;
/* 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. */
...@@ -1265,10 +1199,6 @@ thread_across_edge (gimple dummy_cond, ...@@ -1265,10 +1199,6 @@ 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