From 6d08dc702e910635ad2a49e40b0b7e34f4f2090a Mon Sep 17 00:00:00 2001 From: Pavel Chupin Date: Thu, 1 Nov 2012 16:11:23 +0400 Subject: Fix dom optimization which removes goto in dalvik dexopt Can be seen in logcat by messages: E dalvikvm: Out-of-order map item: 0 then 0x70 E dalvikvm: ERROR: Byte swap + verify failed BZ: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54985 Backport r192745 and children r192746, r192754, r192852: 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. Change-Id: I45e0185b1b729de91749272d62d3d331fcf1cf71 Signed-off-by: Pavel Chupin --- .../gcc/testsuite/gcc.c-torture/execute/pr54985.c | 36 +++++++++++ gcc-4.7/gcc/tree-ssa-threadedge.c | 72 ++++++++++++++++------ 2 files changed, 89 insertions(+), 19 deletions(-) create mode 100644 gcc-4.7/gcc/testsuite/gcc.c-torture/execute/pr54985.c diff --git a/gcc-4.7/gcc/testsuite/gcc.c-torture/execute/pr54985.c b/gcc-4.7/gcc/testsuite/gcc.c-torture/execute/pr54985.c new file mode 100644 index 000000000..678c9f47a --- /dev/null +++ b/gcc-4.7/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-4.7/gcc/tree-ssa-threadedge.c b/gcc-4.7/gcc/tree-ssa-threadedge.c index 707c8df3e..81bf73de6 100644 --- a/gcc-4.7/gcc/tree-ssa-threadedge.c +++ b/gcc-4.7/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