From 8f895cf1ac7babe0c89533e8e9e6b6ca6bb33950 Mon Sep 17 00:00:00 2001 From: Jeff Law Date: Fri, 13 Feb 2015 14:09:58 -0700 Subject: [PATCH] re PR tree-optimization/64823 (false "may be used uninitialized", missed jump threading) PR tree-optimization/64823 * tree-vrp.c (identify_jump_threads): Handle blocks with no statements. * tree-ssa-threadedge.c (potentially_threadable_block): Allow threading through blocks with PHIs, but no statements. (thread_through_normal_block): Distinguish between blocks where we did not process all the statements and blocks with no statements. PR tree-optimization/64823 gcc.dg/uninit-20.c: New test. From-SVN: r220696 --- gcc/ChangeLog | 7 ++++++ gcc/testsuite/ChangeLog | 3 +++ gcc/testsuite/gcc.dg/uninit-20.c | 18 +++++++++++++++ gcc/tree-ssa-threadedge.c | 39 ++++++++++++++++++++++++++------ gcc/tree-vrp.c | 11 +++++++-- 5 files changed, 69 insertions(+), 9 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/uninit-20.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f36e16c1514..a574c2b06a3 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,12 @@ 2015-02-13 Jeff Law + PR tree-optimization/64823 + * tree-vrp.c (identify_jump_threads): Handle blocks with no statements. + * tree-ssa-threadedge.c (potentially_threadable_block): Allow + threading through blocks with PHIs, but no statements. + (thread_through_normal_block): Distinguish between blocks where + we did not process all the statements and blocks with no statements. + PR rtl-optimization/47477 * match.pd (convert (plus/minus (convert @0) (convert @1): New simplifier to narrow arithmetic. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 2fe9698f34c..f700bb1d227 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,8 @@ 2015-02-13 Jeff Law + PR tree-optimization/64823 + gcc.dg/uninit-20.c: New test. + PR rtl-optimization/47477 * gcc.dg/tree-ssa/pr47477.c: New test. diff --git a/gcc/testsuite/gcc.dg/uninit-20.c b/gcc/testsuite/gcc.dg/uninit-20.c new file mode 100644 index 00000000000..12001aee993 --- /dev/null +++ b/gcc/testsuite/gcc.dg/uninit-20.c @@ -0,0 +1,18 @@ +/* Spurious uninitialized variable warnings, from gdb */ +/* { dg-do compile } */ +/* { dg-options "-O2 -Wuninitialized" } */ +struct os { struct o *o; }; +struct o { struct o *next; struct os *se; }; +void f(struct o *o){ + struct os *s; + if(o) s = o->se; + while(o && s == o->se){ + s++; // here `o' is non-zero and thus s is initialized + s == o->se // `?' is essential, `if' does not trigger the warning + ? (o = o->next, o ? s = o->se : 0) + : 0; + } +} + + + diff --git a/gcc/tree-ssa-threadedge.c b/gcc/tree-ssa-threadedge.c index 4f839910a84..7187d065e91 100644 --- a/gcc/tree-ssa-threadedge.c +++ b/gcc/tree-ssa-threadedge.c @@ -110,6 +110,15 @@ potentially_threadable_block (basic_block bb) { gimple_stmt_iterator gsi; + /* Special case. We can get blocks that are forwarders, but are + not optimized away because they forward from outside a loop + to the loop header. We want to thread through them as we can + sometimes thread to the loop exit, which is obviously profitable. + the interesting case here is when the block has PHIs. */ + if (gsi_end_p (gsi_start_nondebug_bb (bb)) + && !gsi_end_p (gsi_start_phis (bb))) + return true; + /* If BB has a single successor or a single predecessor, then there is no threading opportunity. */ if (single_succ_p (bb) || single_pred_p (bb)) @@ -1281,16 +1290,32 @@ thread_through_normal_block (edge e, = record_temporary_equivalences_from_stmts_at_dest (e, stack, simplify, *backedge_seen_p); - /* 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's two reasons STMT might be null, and distinguishing + between them is important. - Also note if we do not look at all the statements, then we may not - have invalidated equivalences that are no longer valid if we threaded - around a loop. Thus we must signal to our caller that this block - is not suitable for use as a joiner in a threading path. */ + First the block may not have had any statements. For example, it + might have some PHIs and unconditionally transfer control elsewhere. + Such blocks are suitable for jump threading, particularly as a + joiner block. + + The second reason would be if we did not process all the statements + in the block (because there were too many to make duplicating the + block profitable. If we did not look at all the statements, then + we may not have invalidated everything needing invalidation. Thus + we must signal to our caller that this block is not suitable for + use as a joiner in a threading path. */ if (!stmt) - return -1; + { + /* First case. The statement simply doesn't have any instructions, but + does have PHIs. */ + if (gsi_end_p (gsi_start_nondebug_bb (e->dest)) + && !gsi_end_p (gsi_start_phis (e->dest))) + return 0; + /* Second case. */ + return -1; + } + /* If we stopped at a COND_EXPR or SWITCH_EXPR, see if we know which arm will be taken. */ if (gimple_code (stmt) == GIMPLE_COND diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index dad1830e9a1..7367684f4b4 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -10181,8 +10181,15 @@ identify_jump_threads (void) /* We're basically looking for a switch or any kind of conditional with integral or pointer type arguments. Note the type of the second argument will be the same as the first argument, so no need to - check it explicitly. */ - if (gimple_code (last) == GIMPLE_SWITCH + check it explicitly. + + We also handle the case where there are no statements in the + block. This come up with forwarder blocks that are not + optimized away because they lead to a loop header. But we do + want to thread through them as we can sometimes thread to the + loop exit which is obviously profitable. */ + if (!last + || gimple_code (last) == GIMPLE_SWITCH || (gimple_code (last) == GIMPLE_COND && TREE_CODE (gimple_cond_lhs (last)) == SSA_NAME && (INTEGRAL_TYPE_P (TREE_TYPE (gimple_cond_lhs (last))) -- 2.30.2