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 real 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: r220743
This commit is contained in:
parent
ed89033d7c
commit
215f8d9eb3
@ -1,3 +1,13 @@
|
||||
2015-02-16 Jeff Law <law@redhat.com>
|
||||
|
||||
PR tree-optimization/64823
|
||||
* tree-vrp.c (identify_jump_threads): Handle blocks with no real
|
||||
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.
|
||||
|
||||
2015-02-16 Jakub Jelinek <jakub@redhat.com>
|
||||
James Greenhalgh <james.greenhalgh@arm.com>
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
2015-02-16 Jeff Law <law@redhat.com>
|
||||
|
||||
PR tree-optimization/64823
|
||||
* gcc.dg/uninit-20.c: New test.
|
||||
|
||||
2015-02-16 Jakub Jelinek <jakub@redhat.com>
|
||||
James Greenhalgh <james.greenhalgh@arm.com>
|
||||
|
||||
|
18
gcc/testsuite/gcc.dg/uninit-20.c
Normal file
18
gcc/testsuite/gcc.dg/uninit-20.c
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -10176,13 +10176,20 @@ identify_jump_threads (void)
|
||||
/* We only care about blocks ending in a COND_EXPR. While there
|
||||
may be some value in handling SWITCH_EXPR here, I doubt it's
|
||||
terribly important. */
|
||||
last = gsi_stmt (gsi_last_bb (bb));
|
||||
last = gsi_stmt (gsi_last_nondebug_bb (bb));
|
||||
|
||||
/* 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)))
|
||||
|
Loading…
Reference in New Issue
Block a user