re PR rtl-optimization/56181 (ICE in verify_loop_structure, at cfgloop.c:1581 with -ftracer)

2013-02-08  Richard Biener  <rguenther@suse.de>

	PR middle-end/56181
	* cfgloop.h (flow_loops_find): Adjust.
	(bb_loop_header_p): Declare.
	* cfgloop.c (bb_loop_header_p): New function split out from ...
	(flow_loops_find): ... here.  Adjust function signature,
	support incremental loop structure update.
	(verify_loop_structure): Cleanup.  Verify a loop is a loop.
	* cfgloopmanip.c (fix_loop_structure): Move ...
	* loop-init.c (fix_loop_structure): ... here.
	(apply_loop_flags): Split out from ...
	(loop_optimizer_init): ... here.
	(fix_loop_structure): Use apply_loop_flags.  Use flow_loops_find
	in incremental mode, only remove dead loops here.

	* gcc.dg/torture/pr56181.c: New testcase.

From-SVN: r195879
This commit is contained in:
Richard Biener 2013-02-08 11:00:26 +00:00 committed by Richard Biener
parent 85d768f349
commit 0375167b6c
7 changed files with 309 additions and 303 deletions

View File

@ -1,3 +1,19 @@
2013-02-08 Richard Biener <rguenther@suse.de>
PR middle-end/56181
* cfgloop.h (flow_loops_find): Adjust.
(bb_loop_header_p): Declare.
* cfgloop.c (bb_loop_header_p): New function split out from ...
(flow_loops_find): ... here. Adjust function signature,
support incremental loop structure update.
(verify_loop_structure): Cleanup. Verify a loop is a loop.
* cfgloopmanip.c (fix_loop_structure): Move ...
* loop-init.c (fix_loop_structure): ... here.
(apply_loop_flags): Split out from ...
(loop_optimizer_init): ... here.
(fix_loop_structure): Use apply_loop_flags. Use flow_loops_find
in incremental mode, only remove dead loops here.
2013-02-08 Georg-Johann Lay <avr@gjlay.de>
PR target/54222

View File

@ -359,139 +359,156 @@ init_loops_structure (struct loops *loops, unsigned num_loops)
loops->tree_root = root;
}
/* Returns whether HEADER is a loop header. */
bool
bb_loop_header_p (basic_block header)
{
edge_iterator ei;
edge e;
/* If we have an abnormal predecessor, do not consider the
loop (not worth the problems). */
if (bb_has_abnormal_pred (header))
return false;
/* Look for back edges where a predecessor is dominated
by this block. A natural loop has a single entry
node (header) that dominates all the nodes in the
loop. It also has single back edge to the header
from a latch node. */
FOR_EACH_EDGE (e, ei, header->preds)
{
basic_block latch = e->src;
if (latch != ENTRY_BLOCK_PTR
&& dominated_by_p (CDI_DOMINATORS, latch, header))
return true;
}
return false;
}
/* Find all the natural loops in the function and save in LOOPS structure and
recalculate loop_father information in basic block structures.
Return the number of natural loops found. */
If LOOPS is non-NULL then the loop structures for already recorded loops
will be re-used and their number will not change. We assume that no
stale loops exist in LOOPS.
When LOOPS is NULL it is allocated and re-built from scratch.
Return the built LOOPS structure. */
int
struct loops *
flow_loops_find (struct loops *loops)
{
int b;
int num_loops;
edge e;
sbitmap headers;
int *dfs_order;
bool from_scratch = (loops == NULL);
int *rc_order;
basic_block header;
basic_block bb;
int b;
unsigned i;
vec<loop_p> larray;
/* Ensure that the dominators are computed. */
calculate_dominance_info (CDI_DOMINATORS);
if (!loops)
{
loops = ggc_alloc_cleared_loops ();
init_loops_structure (loops, 1);
}
/* Ensure that loop exits were released. */
gcc_assert (loops->exits == NULL);
/* Taking care of this degenerate case makes the rest of
this code simpler. */
if (n_basic_blocks == NUM_FIXED_BLOCKS)
return loops;
/* The root loop node contains all basic-blocks. */
loops->tree_root->num_nodes = n_basic_blocks;
/* Compute depth first search order of the CFG so that outer
natural loops will be found before inner natural loops. */
rc_order = XNEWVEC (int, n_basic_blocks);
pre_and_rev_post_order_compute (NULL, rc_order, false);
/* Gather all loop headers in reverse completion order and allocate
loop structures for loops that are not already present. */
larray.create (loops->larray->length());
for (b = 0; b < n_basic_blocks - NUM_FIXED_BLOCKS; b++)
{
init_loops_structure (loops, 1);
return 1;
basic_block header = BASIC_BLOCK (rc_order[b]);
if (bb_loop_header_p (header))
{
struct loop *loop;
/* The current active loop tree has valid loop-fathers for
header blocks. */
if (!from_scratch
&& header->loop_father->header == header)
{
loop = header->loop_father;
/* If we found an existing loop remove it from the
loop tree. It is going to be inserted again
below. */
flow_loop_tree_node_remove (loop);
}
else
{
/* Otherwise allocate a new loop structure for the loop. */
loop = alloc_loop ();
/* ??? We could re-use unused loop slots here. */
loop->num = loops->larray->length ();
vec_safe_push (loops->larray, loop);
loop->header = header;
if (!from_scratch
&& dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "flow_loops_find: discovered new "
"loop %d with header %d\n",
loop->num, header->index);
}
larray.safe_push (loop);
}
/* Make blocks part of the loop root node at start. */
header->loop_father = loops->tree_root;
}
dfs_order = NULL;
rc_order = NULL;
free (rc_order);
/* Count the number of loop headers. This should be the
same as the number of natural loops. */
headers = sbitmap_alloc (last_basic_block);
bitmap_clear (headers);
num_loops = 0;
FOR_EACH_BB (header)
/* Now iterate over the loops found, insert them into the loop tree
and assign basic-block ownership. */
for (i = 0; i < larray.length (); ++i)
{
struct loop *loop = larray[i];
basic_block header = loop->header;
edge_iterator ei;
edge e;
/* If we have an abnormal predecessor, do not consider the
loop (not worth the problems). */
if (bb_has_abnormal_pred (header))
continue;
flow_loop_tree_node_add (header->loop_father, loop);
loop->num_nodes = flow_loop_nodes_find (loop->header, loop);
/* Look for the latch for this header block, if it has just a
single one. */
FOR_EACH_EDGE (e, ei, header->preds)
{
basic_block latch = e->src;
gcc_assert (!(e->flags & EDGE_ABNORMAL));
/* Look for back edges where a predecessor is dominated
by this block. A natural loop has a single entry
node (header) that dominates all the nodes in the
loop. It also has single back edge to the header
from a latch node. */
if (latch != ENTRY_BLOCK_PTR
&& dominated_by_p (CDI_DOMINATORS, latch, header))
if (flow_bb_inside_loop_p (loop, latch))
{
/* Shared headers should be eliminated by now. */
bitmap_set_bit (headers, header->index);
num_loops++;
}
}
}
/* Allocate loop structures. */
init_loops_structure (loops, num_loops + 1);
/* Find and record information about all the natural loops
in the CFG. */
FOR_EACH_BB (bb)
bb->loop_father = loops->tree_root;
if (num_loops)
{
/* Compute depth first search order of the CFG so that outer
natural loops will be found before inner natural loops. */
dfs_order = XNEWVEC (int, n_basic_blocks);
rc_order = XNEWVEC (int, n_basic_blocks);
pre_and_rev_post_order_compute (dfs_order, rc_order, false);
num_loops = 1;
for (b = 0; b < n_basic_blocks - NUM_FIXED_BLOCKS; b++)
{
struct loop *loop;
edge_iterator ei;
/* Search the nodes of the CFG in reverse completion order
so that we can find outer loops first. */
if (!bitmap_bit_p (headers, rc_order[b]))
continue;
header = BASIC_BLOCK (rc_order[b]);
loop = alloc_loop ();
loops->larray->quick_push (loop);
loop->header = header;
loop->num = num_loops;
num_loops++;
flow_loop_tree_node_add (header->loop_father, loop);
loop->num_nodes = flow_loop_nodes_find (loop->header, loop);
/* Look for the latch for this header block, if it has just a
single one. */
FOR_EACH_EDGE (e, ei, header->preds)
{
basic_block latch = e->src;
if (flow_bb_inside_loop_p (loop, latch))
if (loop->latch != NULL)
{
if (loop->latch != NULL)
{
/* More than one latch edge. */
loop->latch = NULL;
break;
}
loop->latch = latch;
/* More than one latch edge. */
loop->latch = NULL;
break;
}
loop->latch = latch;
}
}
free (dfs_order);
free (rc_order);
}
sbitmap_free (headers);
larray.release();
loops->exits = NULL;
return loops->larray->length ();
return loops;
}
/* Ratio of frequencies of edges so that one of more latch edges is
@ -1300,7 +1317,7 @@ verify_loop_structure (void)
{
unsigned *sizes, i, j;
sbitmap irreds;
basic_block *bbs, bb;
basic_block bb;
struct loop *loop;
int err = 0;
edge e;
@ -1308,7 +1325,7 @@ verify_loop_structure (void)
loop_iterator li;
struct loop_exit *exit, *mexit;
bool dom_available = dom_info_available_p (CDI_DOMINATORS);
sbitmap visited = sbitmap_alloc (last_basic_block);
sbitmap visited;
/* We need up-to-date dominators, compute or verify them. */
if (!dom_available)
@ -1337,28 +1354,23 @@ verify_loop_structure (void)
}
/* Check get_loop_body. */
FOR_EACH_LOOP (li, loop, 0)
{
bbs = get_loop_body (loop);
for (j = 0; j < loop->num_nodes; j++)
if (!flow_bb_inside_loop_p (loop, bbs[j]))
{
error ("bb %d does not belong to loop %d",
bbs[j]->index, loop->num);
err = 1;
}
free (bbs);
}
visited = sbitmap_alloc (last_basic_block);
bitmap_clear (visited);
FOR_EACH_LOOP (li, loop, LI_FROM_INNERMOST)
{
bbs = get_loop_body (loop);
basic_block *bbs = get_loop_body (loop);
for (j = 0; j < loop->num_nodes; j++)
{
bb = bbs[j];
if (!flow_bb_inside_loop_p (loop, bb))
{
error ("bb %d does not belong to loop %d",
bb->index, loop->num);
err = 1;
}
/* Ignore this block if it is in an inner loop. */
if (bitmap_bit_p (visited, bb->index))
continue;
@ -1371,14 +1383,21 @@ verify_loop_structure (void)
err = 1;
}
}
free (bbs);
}
sbitmap_free (visited);
/* Check headers and latches. */
FOR_EACH_LOOP (li, loop, 0)
{
i = loop->num;
if (!bb_loop_header_p (loop->header))
{
error ("loop %d%'s header is not a loop header", i);
err = 1;
}
if (loops_state_satisfies_p (LOOPS_HAVE_PREHEADERS)
&& EDGE_COUNT (loop->header->preds) != 2)
{
@ -1585,7 +1604,6 @@ verify_loop_structure (void)
gcc_assert (!err);
sbitmap_free (visited);
free (sizes);
if (!dom_available)
free_dominance_info (CDI_DOMINATORS);

View File

@ -205,7 +205,8 @@ struct GTY (()) loops {
};
/* Loop recognition. */
extern int flow_loops_find (struct loops *);
bool bb_loop_header_p (basic_block);
extern struct loops *flow_loops_find (struct loops *);
extern void disambiguate_loops_with_multiple_latches (void);
extern void flow_loops_free (struct loops *);
extern void flow_loops_dump (FILE *,

View File

@ -1760,159 +1760,3 @@ loop_version (struct loop *loop,
return nloop;
}
/* The structure of loops might have changed. Some loops might get removed
(and their headers and latches were set to NULL), loop exists might get
removed (thus the loop nesting may be wrong), and some blocks and edges
were changed (so the information about bb --> loop mapping does not have
to be correct). But still for the remaining loops the header dominates
the latch, and loops did not get new subloops (new loops might possibly
get created, but we are not interested in them). Fix up the mess.
If CHANGED_BBS is not NULL, basic blocks whose loop has changed are
marked in it. */
void
fix_loop_structure (bitmap changed_bbs)
{
basic_block bb;
struct loop *loop, *ploop;
loop_iterator li;
bool record_exits = false;
struct loop **superloop = XNEWVEC (struct loop *, number_of_loops ());
/* We need exact and fast dominance info to be available. */
gcc_assert (dom_info_state (CDI_DOMINATORS) == DOM_OK);
/* Remove the old bb -> loop mapping. Remember the depth of the blocks in
the loop hierarchy, so that we can recognize blocks whose loop nesting
relationship has changed. */
FOR_EACH_BB (bb)
{
if (changed_bbs)
bb->aux = (void *) (size_t) loop_depth (bb->loop_father);
bb->loop_father = current_loops->tree_root;
}
if (loops_state_satisfies_p (LOOPS_HAVE_RECORDED_EXITS))
{
release_recorded_exits ();
record_exits = true;
}
/* First re-compute loop latches. */
FOR_EACH_LOOP (li, loop, 0)
{
edge_iterator ei;
edge e, first_latch = NULL, latch = NULL;
if (!loop->header)
continue;
FOR_EACH_EDGE (e, ei, loop->header->preds)
if (dominated_by_p (CDI_DOMINATORS, e->src, loop->header))
{
if (!first_latch)
first_latch = latch = e;
else
{
latch = NULL;
break;
}
}
/* If there was no latch, schedule the loop for removal. */
if (!first_latch)
loop->header = NULL;
/* If there was a single latch, record it. */
else if (latch)
loop->latch = latch->src;
/* Otherwise there are multiple latches which are eventually
disambiguated below. */
else
loop->latch = NULL;
}
/* Remove the dead loops from structures. We start from the innermost
loops, so that when we remove the loops, we know that the loops inside
are preserved, and do not waste time relinking loops that will be
removed later. */
FOR_EACH_LOOP (li, loop, LI_FROM_INNERMOST)
{
if (loop->header)
continue;
while (loop->inner)
{
ploop = loop->inner;
flow_loop_tree_node_remove (ploop);
flow_loop_tree_node_add (loop_outer (loop), ploop);
}
/* Remove the loop and free its data. */
delete_loop (loop);
}
/* Rescan the bodies of loops, starting from the outermost ones. We assume
that no optimization interchanges the order of the loops, i.e., it cannot
happen that L1 was superloop of L2 before and it is subloop of L2 now
(without explicitly updating loop information). At the same time, we also
determine the new loop structure. */
current_loops->tree_root->num_nodes = n_basic_blocks;
FOR_EACH_LOOP (li, loop, 0)
{
superloop[loop->num] = loop->header->loop_father;
loop->num_nodes = flow_loop_nodes_find (loop->header, loop);
}
/* Now fix the loop nesting. */
FOR_EACH_LOOP (li, loop, 0)
{
ploop = superloop[loop->num];
if (ploop != loop_outer (loop))
{
flow_loop_tree_node_remove (loop);
flow_loop_tree_node_add (ploop, loop);
}
}
free (superloop);
/* Mark the blocks whose loop has changed. */
if (changed_bbs)
{
FOR_EACH_BB (bb)
{
if ((void *) (size_t) loop_depth (bb->loop_father) != bb->aux)
bitmap_set_bit (changed_bbs, bb->index);
bb->aux = NULL;
}
}
if (!loops_state_satisfies_p (LOOPS_MAY_HAVE_MULTIPLE_LATCHES))
disambiguate_loops_with_multiple_latches ();
if (loops_state_satisfies_p (LOOPS_HAVE_PREHEADERS))
{
int cp_flags = CP_SIMPLE_PREHEADERS;
if (loops_state_satisfies_p (LOOPS_HAVE_FALLTHRU_PREHEADERS))
cp_flags |= CP_FALLTHRU_PREHEADERS;
create_preheaders (cp_flags);
}
if (loops_state_satisfies_p (LOOPS_HAVE_SIMPLE_LATCHES))
force_single_succ_latches ();
if (loops_state_satisfies_p (LOOPS_HAVE_MARKED_IRREDUCIBLE_REGIONS))
mark_irreducible_loops ();
if (record_exits)
record_loop_exits ();
loops_state_clear (LOOPS_NEED_FIXUP);
#ifdef ENABLE_CHECKING
verify_loop_structure ();
#endif
}

View File

@ -32,37 +32,11 @@ along with GCC; see the file COPYING3. If not see
#include "ggc.h"
/* Initialize loop structures. This is used by the tree and RTL loop
optimizers. FLAGS specify what properties to compute and/or ensure for
loops. */
/* Apply FLAGS to the loop state. */
void
loop_optimizer_init (unsigned flags)
static void
apply_loop_flags (unsigned flags)
{
timevar_push (TV_LOOP_INIT);
if (!current_loops)
{
struct loops *loops = ggc_alloc_cleared_loops ();
gcc_assert (!(cfun->curr_properties & PROP_loops));
/* Find the loops. */
flow_loops_find (loops);
current_loops = loops;
}
else
{
gcc_assert (cfun->curr_properties & PROP_loops);
/* Ensure that the dominators are computed, like flow_loops_find does. */
calculate_dominance_info (CDI_DOMINATORS);
#ifdef ENABLE_CHECKING
verify_loop_structure ();
#endif
}
if (flags & LOOPS_MAY_HAVE_MULTIPLE_LATCHES)
{
/* If the loops may have multiple latches, we cannot canonicalize
@ -97,6 +71,38 @@ loop_optimizer_init (unsigned flags)
if (flags & LOOPS_HAVE_RECORDED_EXITS)
record_loop_exits ();
}
/* Initialize loop structures. This is used by the tree and RTL loop
optimizers. FLAGS specify what properties to compute and/or ensure for
loops. */
void
loop_optimizer_init (unsigned flags)
{
timevar_push (TV_LOOP_INIT);
if (!current_loops)
{
gcc_assert (!(cfun->curr_properties & PROP_loops));
/* Find the loops. */
current_loops = flow_loops_find (NULL);
}
else
{
gcc_assert (cfun->curr_properties & PROP_loops);
/* Ensure that the dominators are computed, like flow_loops_find does. */
calculate_dominance_info (CDI_DOMINATORS);
#ifdef ENABLE_CHECKING
verify_loop_structure ();
#endif
}
/* Apply flags to loops. */
apply_loop_flags (flags);
/* Dump loops. */
flow_loops_dump (dump_file, NULL, 1);
@ -157,6 +163,97 @@ loop_fini_done:
timevar_pop (TV_LOOP_FINI);
}
/* The structure of loops might have changed. Some loops might get removed
(and their headers and latches were set to NULL), loop exists might get
removed (thus the loop nesting may be wrong), and some blocks and edges
were changed (so the information about bb --> loop mapping does not have
to be correct). But still for the remaining loops the header dominates
the latch, and loops did not get new subloops (new loops might possibly
get created, but we are not interested in them). Fix up the mess.
If CHANGED_BBS is not NULL, basic blocks whose loop has changed are
marked in it. */
void
fix_loop_structure (bitmap changed_bbs)
{
basic_block bb;
int record_exits = 0;
loop_iterator li;
struct loop *loop;
timevar_push (TV_LOOP_INIT);
/* We need exact and fast dominance info to be available. */
gcc_assert (dom_info_state (CDI_DOMINATORS) == DOM_OK);
if (loops_state_satisfies_p (LOOPS_HAVE_RECORDED_EXITS))
{
release_recorded_exits ();
record_exits = LOOPS_HAVE_RECORDED_EXITS;
}
/* Remember the depth of the blocks in the loop hierarchy, so that we can
recognize blocks whose loop nesting relationship has changed. */
if (changed_bbs)
FOR_EACH_BB (bb)
bb->aux = (void *) (size_t) loop_depth (bb->loop_father);
/* Remove the dead loops from structures. We start from the innermost
loops, so that when we remove the loops, we know that the loops inside
are preserved, and do not waste time relinking loops that will be
removed later. */
FOR_EACH_LOOP (li, loop, LI_FROM_INNERMOST)
{
/* Detect the case that the loop is no longer present even though
it wasn't marked for removal.
??? If we do that we can get away with not marking loops for
removal at all. And possibly avoid some spurious removals. */
if (loop->header
&& bb_loop_header_p (loop->header))
continue;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "fix_loop_structure: removing loop %d\n",
loop->num);
while (loop->inner)
{
struct loop *ploop = loop->inner;
flow_loop_tree_node_remove (ploop);
flow_loop_tree_node_add (loop_outer (loop), ploop);
}
/* Remove the loop and free its data. */
delete_loop (loop);
}
/* Re-compute loop structure in-place. */
flow_loops_find (current_loops);
/* Mark the blocks whose loop has changed. */
if (changed_bbs)
{
FOR_EACH_BB (bb)
{
if ((void *) (size_t) loop_depth (bb->loop_father) != bb->aux)
bitmap_set_bit (changed_bbs, bb->index);
bb->aux = NULL;
}
}
loops_state_clear (LOOPS_NEED_FIXUP);
/* Apply flags to loops. */
apply_loop_flags (current_loops->state | record_exits);
#ifdef ENABLE_CHECKING
verify_loop_structure ();
#endif
timevar_pop (TV_LOOP_INIT);
}
/* Gate for the RTL loop superpass. The actual passes are subpasses.
See passes.c for more on that. */

View File

@ -1,3 +1,8 @@
2013-02-08 Richard Biener <rguenther@suse.de>
PR middle-end/56181
* gcc.dg/torture/pr56181.c: New testcase.
2013-02-08 Georg-Johann Lay <avr@gjlay.de>
PR target/54222

View File

@ -0,0 +1,25 @@
/* { dg-do compile } */
/* { dg-options "-ftracer" } */
int a, b;
void f(void)
{
if(a++)
{
for(a = 0; a < 1;)
{
for(b = 0; b < 1; b++)
{
while(a++ < 0);
lbl:
;
}
if(a)
goto lbl;
}
goto lbl;
}
}