Commit c0258754 by Jeff Law Committed by Jeff Law

re PR tree-optimization/54985 (dom optimization erroneous remove conditional goto.)

        PR tree-optimization/54985
        * tree-ssa-threadedge.c (cond_arg_set_in_bb): New function
        * extracted
        from thread_across_edge.
        (thread_across_edge): Use it in all cases where we might thread
        across a back edge.

        * gcc.c-torture/execute/pr54985.c: New test.

From-SVN: r192745
parent 44b94bdb
2012-10-23 Jeff Law <law@redhat.com>
PR tree-optimization/54985
* tree-ssa-threadedge.c (cond_arg_set_in_bb): New function extracted
from thread_across_edge.
(thread_across_edge): Use it in all cases where we might thread
across a back edge.
2012-10-23 Vladimir Makarov <vmakarov@redhat.com> 2012-10-23 Vladimir Makarov <vmakarov@redhat.com>
* lra-constraints.c (update_ebb_live_info): Process empty blocks. * lra-constraints.c (update_ebb_live_info): Process empty blocks.
2012-10-23 Jeff Law <law@redhat.com>
* gcc.c-torture/execute/pr54985.c: New test.
2012-10-23 Paul Koning <ni1d@arrl.net> 2012-10-23 Paul Koning <ni1d@arrl.net>
PR debug/54508 PR debug/54508
......
typedef struct st {
int a;
} ST;
int __attribute__((noinline,noclone))
foo(ST *s, int c)
{
int first = 1;
int count = c;
ST *item = s;
int a = s->a;
int x;
while (count--)
{
x = item->a;
if (first)
first = 0;
else if (x >= a)
return 1;
a = x;
item++;
}
return 0;
}
extern void abort (void);
int main ()
{
ST _1[2] = {{2}, {1}};
if (foo(_1, 2) != 0)
abort ();
return 0;
}
...@@ -572,6 +572,44 @@ simplify_control_stmt_condition (edge e, ...@@ -572,6 +572,44 @@ 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, int n)
{
ssa_op_iter iter;
use_operand_p use_p;
gimple last = gsi_stmt (gsi_last_bb (e->dest));
/* E->dest does not have to end with a control transferring
instruction. This can occurr 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;
}
/* TAKEN_EDGE represents the an edge taken as a result of jump threading. /* TAKEN_EDGE represents the an edge taken as a result of jump threading.
See if we can thread around TAKEN_EDGE->dest as well. If so, return See if we can thread around TAKEN_EDGE->dest as well. If so, return
the edge out of TAKEN_EDGE->dest that we can statically compute will be the edge out of TAKEN_EDGE->dest that we can statically compute will be
...@@ -705,19 +743,8 @@ thread_across_edge (gimple dummy_cond, ...@@ -705,19 +743,8 @@ thread_across_edge (gimple dummy_cond,
safe to thread this edge. */ safe to thread this edge. */
if (e->flags & EDGE_DFS_BACK) if (e->flags & EDGE_DFS_BACK)
{ {
ssa_op_iter iter; if (cond_arg_set_in_bb (e, e->dest, 1))
use_operand_p use_p; goto fail;
gimple last = gsi_stmt (gsi_last_bb (e->dest));
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)) == e->dest)
goto fail;
}
} }
stmt_count = 0; stmt_count = 0;
...@@ -758,7 +785,9 @@ thread_across_edge (gimple dummy_cond, ...@@ -758,7 +785,9 @@ thread_across_edge (gimple dummy_cond,
address. If DEST is not null, then see if we can thread address. If DEST is not null, then see if we can thread
through it as well, this helps capture secondary effects through it as well, this helps capture secondary effects
of threading without having to re-run DOM or VRP. */ of threading without having to re-run DOM or VRP. */
if (dest) if (dest
&& ((e->flags & EDGE_DFS_BACK) == 0
|| ! cond_arg_set_in_bb (taken_edge, e->dest, 2)))
{ {
/* We don't want to thread back to a block we have already /* We don't want to thread back to a block we have already
visited. This may be overly conservative. */ visited. This may be overly conservative. */
...@@ -816,11 +845,16 @@ thread_across_edge (gimple dummy_cond, ...@@ -816,11 +845,16 @@ thread_across_edge (gimple dummy_cond,
e3 = taken_edge; e3 = taken_edge;
do do
{ {
e2 = thread_around_empty_block (e3, if ((e->flags & EDGE_DFS_BACK) == 0
dummy_cond, || ! cond_arg_set_in_bb (e3, e->dest, 3))
handle_dominating_asserts, e2 = thread_around_empty_block (e3,
simplify, dummy_cond,
visited); handle_dominating_asserts,
simplify,
visited);
else
e2 = NULL;
if (e2) if (e2)
{ {
e3 = e2; e3 = e2;
......
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