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: r193108
This commit is contained in:
parent
e54acbedb8
commit
e8b6f29ec1
|
@ -1,3 +1,11 @@
|
|||
2012-11-02 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-31 Eric Botcazou <ebotcazou@adacore.com>
|
||||
|
||||
* config/i386/i386.c (ix86_expand_prologue): Emit frame info for the
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
2012-11-02 Jeff Law <law@redhat.com>
|
||||
|
||||
* gcc.c-torture/execute/pr54985.c: New test.
|
||||
|
||||
2012-10-29 Eric Botcazou <ebotcazou@adacore.com>
|
||||
|
||||
PR ada/53517
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
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;
|
||||
}
|
|
@ -574,6 +574,44 @@ simplify_control_stmt_condition (edge e,
|
|||
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 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.
|
||||
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
|
||||
|
@ -707,19 +745,8 @@ thread_across_edge (gimple dummy_cond,
|
|||
safe to thread this edge. */
|
||||
if (e->flags & EDGE_DFS_BACK)
|
||||
{
|
||||
ssa_op_iter iter;
|
||||
use_operand_p use_p;
|
||||
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;
|
||||
}
|
||||
if (cond_arg_set_in_bb (e, e->dest))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
stmt_count = 0;
|
||||
|
@ -760,7 +787,9 @@ thread_across_edge (gimple dummy_cond,
|
|||
address. If DEST is not null, then see if we can thread
|
||||
through it as well, this helps capture secondary effects
|
||||
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)))
|
||||
{
|
||||
/* We don't want to thread back to a block we have already
|
||||
visited. This may be overly conservative. */
|
||||
|
@ -818,11 +847,16 @@ thread_across_edge (gimple dummy_cond,
|
|||
e3 = taken_edge;
|
||||
do
|
||||
{
|
||||
e2 = thread_around_empty_block (e3,
|
||||
dummy_cond,
|
||||
handle_dominating_asserts,
|
||||
simplify,
|
||||
visited);
|
||||
if ((e->flags & EDGE_DFS_BACK) == 0
|
||||
|| ! cond_arg_set_in_bb (e3, e->dest))
|
||||
e2 = thread_around_empty_block (e3,
|
||||
dummy_cond,
|
||||
handle_dominating_asserts,
|
||||
simplify,
|
||||
visited);
|
||||
else
|
||||
e2 = NULL;
|
||||
|
||||
if (e2)
|
||||
{
|
||||
e3 = e2;
|
||||
|
|
Loading…
Reference in New Issue