re PR tree-optimization/61009 (Incorrect jump threading in dom)
2014-05-08 Jeff Law <law@redhat.com> PR tree-optimization/61009 * tree-ssa-threadedge.c (thread_through_normal_block): Return a tri-state rather than a boolean. When a block is too big to thread through, inform caller via negative return value. (thread_across_edge): If a block was too big for normal threading, then it's too big for a joiner too, so remove temporary equivalences and return immediately. PR tree-optimization/61009 * g++.dg/tree-ssa/pr61009.C: New test. From-SVN: r210254
This commit is contained in:
parent
db48367c49
commit
0600049c86
4 changed files with 114 additions and 13 deletions
|
@ -1,3 +1,13 @@
|
|||
2014-05-08 Jeff Law <law@redhat.com>
|
||||
|
||||
PR tree-optimization/61009
|
||||
* tree-ssa-threadedge.c (thread_through_normal_block): Return a
|
||||
tri-state rather than a boolean. When a block is too big to
|
||||
thread through, inform caller via negative return value.
|
||||
(thread_across_edge): If a block was too big for normal threading,
|
||||
then it's too big for a joiner too, so remove temporary equivalences
|
||||
and return immediately.
|
||||
|
||||
2014-05-08 Manuel López-Ibáñez <manu@gcc.gnu.org>
|
||||
Matthias Klose <doko@ubuntu.com>
|
||||
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
2014-05-08 Jeff Law <law@redhat.com>
|
||||
|
||||
PR tree-optimization/61009
|
||||
* g++.dg/tree-ssa/pr61009.C: New test.
|
||||
|
||||
2014-05-08 Matthias Klose <doko@ubuntu.com>
|
||||
|
||||
PR driver/61106
|
||||
|
|
53
gcc/testsuite/g++.dg/tree-ssa/pr61009.C
Normal file
53
gcc/testsuite/g++.dg/tree-ssa/pr61009.C
Normal file
|
@ -0,0 +1,53 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fno-tree-vrp -std=c++11 -fno-strict-aliasing -fdump-tree-dom1" } */
|
||||
|
||||
#include <stdio.h>
|
||||
struct Field {
|
||||
virtual int Compare(void*, void*);
|
||||
};
|
||||
extern int NKF, NR;
|
||||
extern int idxs[];
|
||||
extern Field* the_field;
|
||||
extern int *incs;
|
||||
extern char** fptrs;
|
||||
inline int doCmp(int this_row_offset, int field_idx) {
|
||||
void *p = fptrs[field_idx] + this_row_offset * incs[field_idx];
|
||||
return the_field->Compare(p,0);
|
||||
}
|
||||
bool Test(void) {
|
||||
|
||||
int row_offset = 0;
|
||||
|
||||
for (; row_offset < NR; ++row_offset) {
|
||||
|
||||
bool is_different = false;
|
||||
for (int j = 0; j < NKF ; ++j) {
|
||||
int field_idx = idxs[j];
|
||||
int cmp = doCmp(row_offset, field_idx);
|
||||
fprintf (stderr, "cmp=%d\n",cmp);
|
||||
|
||||
if (cmp == 0) {
|
||||
continue;
|
||||
}
|
||||
if (cmp > 0) {
|
||||
is_different = true;
|
||||
break;
|
||||
} else {
|
||||
fprintf (stderr, "Incorrect\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!is_different) {
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// The block ending with cmp == 0 should not be threaded. ie,
|
||||
// there should be a single == 0 comparison in the dump file.
|
||||
|
||||
// { dg-final { scan-tree-dump-times "== 0" 1 "dom1" } }
|
||||
// { dg-final { cleanup-tree-dump "dom1" } }
|
|
@ -966,9 +966,14 @@ thread_around_empty_blocks (edge taken_edge,
|
|||
SIMPLIFY is a pass-specific function used to simplify statements.
|
||||
|
||||
Our caller is responsible for restoring the state of the expression
|
||||
and const_and_copies stacks. */
|
||||
and const_and_copies stacks.
|
||||
|
||||
static bool
|
||||
Positive return value is success. Zero return value is failure, but
|
||||
the block can still be duplicated as a joiner in a jump thread path,
|
||||
negative indicates the block should not be duplicated and thus is not
|
||||
suitable for a joiner in a jump threading path. */
|
||||
|
||||
static int
|
||||
thread_through_normal_block (edge e,
|
||||
gimple dummy_cond,
|
||||
bool handle_dominating_asserts,
|
||||
|
@ -990,7 +995,7 @@ thread_through_normal_block (edge e,
|
|||
/* PHIs create temporary equivalences. */
|
||||
if (!record_temporary_equivalences_from_phis (e, stack, *backedge_seen_p,
|
||||
src_map, dst_map))
|
||||
return false;
|
||||
return 0;
|
||||
|
||||
/* Now walk each statement recording any context sensitive
|
||||
temporary equivalences we can detect. */
|
||||
|
@ -998,8 +1003,16 @@ thread_through_normal_block (edge e,
|
|||
= record_temporary_equivalences_from_stmts_at_dest (e, stack, simplify,
|
||||
*backedge_seen_p,
|
||||
src_map, dst_map);
|
||||
|
||||
/* 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.
|
||||
|
||||
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. */
|
||||
if (!stmt)
|
||||
return false;
|
||||
return -1;
|
||||
|
||||
/* If we stopped at a COND_EXPR or SWITCH_EXPR, see if we know which arm
|
||||
will be taken. */
|
||||
|
@ -1023,7 +1036,7 @@ thread_through_normal_block (edge e,
|
|||
if (dest == NULL
|
||||
|| dest == e->dest
|
||||
|| bitmap_bit_p (visited, dest->index))
|
||||
return false;
|
||||
return 0;
|
||||
|
||||
/* Only push the EDGE_START_JUMP_THREAD marker if this is
|
||||
first edge on the path. */
|
||||
|
@ -1057,10 +1070,10 @@ thread_through_normal_block (edge e,
|
|||
visited,
|
||||
path,
|
||||
backedge_seen_p);
|
||||
return true;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We are exiting E->src, see if E->dest ends with a conditional
|
||||
|
@ -1112,9 +1125,12 @@ thread_across_edge (gimple dummy_cond,
|
|||
if (backedge_seen)
|
||||
simplify = dummy_simplify;
|
||||
|
||||
if (thread_through_normal_block (e, dummy_cond, handle_dominating_asserts,
|
||||
stack, simplify, path, visited,
|
||||
&backedge_seen, src_map, dst_map))
|
||||
int threaded = thread_through_normal_block (e, dummy_cond,
|
||||
handle_dominating_asserts,
|
||||
stack, simplify, path,
|
||||
visited, &backedge_seen,
|
||||
src_map, dst_map);
|
||||
if (threaded > 0)
|
||||
{
|
||||
propagate_threaded_block_debug_into (path->last ()->e->dest,
|
||||
e->dest);
|
||||
|
@ -1127,10 +1143,27 @@ thread_across_edge (gimple dummy_cond,
|
|||
}
|
||||
else
|
||||
{
|
||||
/* There should be no edges on the path, so no need to walk through
|
||||
the vector entries. */
|
||||
/* Negative and zero return values indicate no threading was possible,
|
||||
thus there should be no edges on the thread path and no need to walk
|
||||
through the vector entries. */
|
||||
gcc_assert (path->length () == 0);
|
||||
path->release ();
|
||||
|
||||
/* A negative status indicates the target block was deemed too big to
|
||||
duplicate. Just quit now rather than trying to use the block as
|
||||
a joiner in a jump threading path.
|
||||
|
||||
This prevents unnecessary code growth, but more importantly if we
|
||||
do not look at all the statements in the block, then we may have
|
||||
missed some invalidations if we had traversed a backedge! */
|
||||
if (threaded < 0)
|
||||
{
|
||||
BITMAP_FREE (visited);
|
||||
BITMAP_FREE (src_map);
|
||||
BITMAP_FREE (dst_map);
|
||||
remove_temporary_equivalences (stack);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* We were unable to determine what out edge from E->dest is taken. However,
|
||||
|
@ -1212,7 +1245,7 @@ thread_across_edge (gimple dummy_cond,
|
|||
handle_dominating_asserts,
|
||||
stack, simplify, path, visited,
|
||||
&backedge_seen,
|
||||
src_map, dst_map);
|
||||
src_map, dst_map) > 0;
|
||||
|
||||
/* If we were able to thread through a successor of E->dest, then
|
||||
record the jump threading opportunity. */
|
||||
|
|
Loading…
Add table
Reference in a new issue