From 43a495541968cda004badd45f3937c3155d5846e Mon Sep 17 00:00:00 2001 From: Jeff Law Date: Fri, 2 Nov 2012 20:19:16 +0000 Subject: 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. git-svn-id: https://gcc.gnu.org/svn/gcc/branches/gcc-4_7-branch@193108 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 8 +++ gcc/testsuite/ChangeLog | 4 ++ gcc/testsuite/gcc.c-torture/execute/pr54985.c | 36 ++++++++++++++ gcc/tree-ssa-threadedge.c | 72 ++++++++++++++++++++------- 4 files changed, 101 insertions(+), 19 deletions(-) create mode 100644 gcc/testsuite/gcc.c-torture/execute/pr54985.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 09596915d86..d39545853de 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2012-11-02 Jeff Law + + 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 * config/i386/i386.c (ix86_expand_prologue): Emit frame info for the diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index a63ef894f13..0bc42d3a93f 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2012-11-02 Jeff Law + + * gcc.c-torture/execute/pr54985.c: New test. + 2012-10-29 Eric Botcazou PR ada/53517 diff --git a/gcc/testsuite/gcc.c-torture/execute/pr54985.c b/gcc/testsuite/gcc.c-torture/execute/pr54985.c new file mode 100644 index 00000000000..678c9f47ae7 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/pr54985.c @@ -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; +} diff --git a/gcc/tree-ssa-threadedge.c b/gcc/tree-ssa-threadedge.c index 707c8df3ec5..a2860f6f978 100644 --- a/gcc/tree-ssa-threadedge.c +++ b/gcc/tree-ssa-threadedge.c @@ -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; -- cgit v1.2.3