re PR tree-optimization/59597 (Performance degradation on Coremark after r205074)

PR tree-optimization/59597
	* tree-ssa-threadupdate.c (dump_jump_thread_path): Move to earlier
	in file.  Accept new argument REGISTERING and use it to modify
	dump output appropriately.
	(register_jump_thread): Corresponding changes.
	(mark_threaded_blocks): Reinstate code to cancel unprofitable
	thread paths involving joiner blocks.  Add code to dump cancelled
	jump threading paths.

	PR tree-optimization/59597
	* gcc.dg/tree-ssa/pr59597.c: New test.

From-SVN: r206941
This commit is contained in:
Jeff Law 2014-01-22 14:27:38 -07:00 committed by Jeff Law
parent c3cdd71f45
commit bb50b870a4
4 changed files with 157 additions and 39 deletions

View File

@ -1,3 +1,14 @@
2014-01-22 Jeff Law <law@redhat.com>
PR tree-optimization/59597
* tree-ssa-threadupdate.c (dump_jump_thread_path): Move to earlier
in file. Accept new argument REGISTERING and use it to modify
dump output appropriately.
(register_jump_thread): Corresponding changes.
(mark_threaded_blocks): Reinstate code to cancel unprofitable
thread paths involving joiner blocks. Add code to dump cancelled
jump threading paths.
2014-01-22 Vladimir Makarov <vmakarov@redhat.com>
PR rtl-optimization/59477

View File

@ -1,3 +1,8 @@
2014-01-22 Jeff Law <law@redhat.com>
PR tree-optimization/59597
* gcc.dg/tree-ssa/pr59597.c: New test.
2014-01-22 Vladimir Makarov <vmakarov@redhat.com>
PR rtl-optimization/59477

View File

@ -0,0 +1,55 @@
/* { dg-do compile } */
/* { dg-options "-Ofast -fdump-tree-vrp1-details" } */
typedef unsigned short u16;
typedef unsigned char u8;
typedef unsigned int u32;
#define NNN 10
u32 f[NNN], t[NNN];
u16 Calc_crc8(u8 data, u16 crc )
{
u8 i=0,x16=0,carry=0;
for (i = 0; i < 8; i++)
{
x16 = (u8)((data & 1) ^ ((u8)crc & 1));
data >>= 1;
if (x16 == 1)
{
crc ^= 0x4002;
carry = 1;
}
else
carry = 0;
crc >>= 1;
if (carry)
crc |= 0x8000;
else
crc &= 0x7fff;
}
return crc;
}
int main (int argc, char argv[])
{
int i, j; u16 crc;
for (j = 0; j < 10000000; j++)
{
for (i = 0; i < NNN; i++)
{
f[i] = random(i);
t[i] = random(NNN - i - 1);
}
for (i=0; i<NNN; i++)
{
crc=Calc_crc8(f[i],(u16)argc);
crc=Calc_crc8(t[i],crc);
}
}
return crc;
}
/* { dg-final { scan-tree-dump "Cancelling" "vrp1" } } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -148,6 +148,40 @@ struct redirection_data : typed_free_remove<redirection_data>
static inline int equal (const value_type *, const compare_type *);
};
/* Dump a jump threading path, including annotations about each
edge in the path. */
static void
dump_jump_thread_path (FILE *dump_file, vec<jump_thread_edge *> path,
bool registering)
{
fprintf (dump_file,
" %s jump thread: (%d, %d) incoming edge; ",
(registering ? "Registering" : "Cancelling"),
path[0]->e->src->index, path[0]->e->dest->index);
for (unsigned int i = 1; i < path.length (); i++)
{
/* We can get paths with a NULL edge when the final destination
of a jump thread turns out to be a constant address. We dump
those paths when debugging, so we have to be prepared for that
possibility here. */
if (path[i]->e == NULL)
continue;
if (path[i]->type == EDGE_COPY_SRC_JOINER_BLOCK)
fprintf (dump_file, " (%d, %d) joiner; ",
path[i]->e->src->index, path[i]->e->dest->index);
if (path[i]->type == EDGE_COPY_SRC_BLOCK)
fprintf (dump_file, " (%d, %d) normal;",
path[i]->e->src->index, path[i]->e->dest->index);
if (path[i]->type == EDGE_NO_COPY_SRC_BLOCK)
fprintf (dump_file, " (%d, %d) nocopy;",
path[i]->e->src->index, path[i]->e->dest->index);
}
fputc ('\n', dump_file);
}
/* Simple hashing function. For any given incoming edge E, we're going
to be most concerned with the final destination of its jump thread
path. So hash on the block index of the final edge in the path. */
@ -1394,16 +1428,61 @@ mark_threaded_blocks (bitmap threaded_blocks)
edge e;
edge_iterator ei;
/* Move the jump threading requests from PATHS to each edge
which starts a jump thread path. */
/* It is possible to have jump threads in which one is a subpath
of the other. ie, (A, B), (B, C), (C, D) where B is a joiner
block and (B, C), (C, D) where no joiner block exists.
When this occurs ignore the jump thread request with the joiner
block. It's totally subsumed by the simpler jump thread request.
This results in less block copying, simpler CFGs. More importantly,
when we duplicate the joiner block, B, in this case we will create
a new threading opportunity that we wouldn't be able to optimize
until the next jump threading iteration.
So first convert the jump thread requests which do not require a
joiner block. */
for (i = 0; i < paths.length (); i++)
{
vec<jump_thread_edge *> *path = paths[i];
edge e = (*path)[0]->e;
e->aux = (void *)path;
bitmap_set_bit (tmp, e->dest->index);
if ((*path)[1]->type != EDGE_COPY_SRC_JOINER_BLOCK)
{
edge e = (*path)[0]->e;
e->aux = (void *)path;
bitmap_set_bit (tmp, e->dest->index);
}
}
/* Now iterate again, converting cases where we want to thread
through a joiner block, but only if no other edge on the path
already has a jump thread attached to it. */
for (i = 0; i < paths.length (); i++)
{
vec<jump_thread_edge *> *path = paths[i];
if ((*path)[1]->type == EDGE_COPY_SRC_JOINER_BLOCK)
{
unsigned int j;
for (j = 0; j < path->length (); j++)
if ((*path)[j]->e->aux != NULL)
break;
/* If we iterated through the entire path without exiting the loop,
then we are good to go, attach the path to the starting edge. */
if (j == path->length ())
{
edge e = (*path)[0]->e;
e->aux = path;
bitmap_set_bit (tmp, e->dest->index);
}
else if (dump_file && (dump_flags & TDF_DETAILS))
{
dump_jump_thread_path (dump_file, *path, false);
}
}
}
/* If optimizing for size, only thread through block if we don't have
@ -1712,38 +1791,6 @@ delete_jump_thread_path (vec<jump_thread_edge *> *path)
path->release();
}
/* Dump a jump threading path, including annotations about each
edge in the path. */
static void
dump_jump_thread_path (FILE *dump_file, vec<jump_thread_edge *> path)
{
fprintf (dump_file,
" Registering jump thread: (%d, %d) incoming edge; ",
path[0]->e->src->index, path[0]->e->dest->index);
for (unsigned int i = 1; i < path.length (); i++)
{
/* We can get paths with a NULL edge when the final destination
of a jump thread turns out to be a constant address. We dump
those paths when debugging, so we have to be prepared for that
possibility here. */
if (path[i]->e == NULL)
continue;
if (path[i]->type == EDGE_COPY_SRC_JOINER_BLOCK)
fprintf (dump_file, " (%d, %d) joiner; ",
path[i]->e->src->index, path[i]->e->dest->index);
if (path[i]->type == EDGE_COPY_SRC_BLOCK)
fprintf (dump_file, " (%d, %d) normal;",
path[i]->e->src->index, path[i]->e->dest->index);
if (path[i]->type == EDGE_NO_COPY_SRC_BLOCK)
fprintf (dump_file, " (%d, %d) nocopy;",
path[i]->e->src->index, path[i]->e->dest->index);
}
fputc ('\n', dump_file);
}
/* Register a jump threading opportunity. We queue up all the jump
threading opportunities discovered by a pass and update the CFG
and SSA form all at once.
@ -1770,7 +1817,7 @@ register_jump_thread (vec<jump_thread_edge *> *path)
{
fprintf (dump_file,
"Found NULL edge in jump threading path. Cancelling jump thread:\n");
dump_jump_thread_path (dump_file, *path);
dump_jump_thread_path (dump_file, *path, false);
}
delete_jump_thread_path (path);
@ -1778,7 +1825,7 @@ register_jump_thread (vec<jump_thread_edge *> *path)
}
if (dump_file && (dump_flags & TDF_DETAILS))
dump_jump_thread_path (dump_file, *path);
dump_jump_thread_path (dump_file, *path, true);
if (!paths.exists ())
paths.create (5);