re PR rtl-optimization/27735 (ICE at -O3 caused by loop unswitching)
PR rtl-optimization/27735 * cfgloopmanip.c (fix_loop_placements, fix_bb_placements, unloop): Add new argument to keep track of whether an irreducible region was affected. All callers changed. (fix_irreducible_loops): Removed. (remove_path): Call mark_irreducible_loops if EDGE_IRREDUCIBLE_LOOP flags were invalidated. * gcc.dg/loop-unswitch-1.c: New test. From-SVN: r116582
This commit is contained in:
parent
b0d3a6aeb8
commit
dc14f1915c
4 changed files with 112 additions and 105 deletions
|
@ -1,3 +1,13 @@
|
|||
2006-08-30 Zdenek Dvorak <dvorakz@suse.cz>
|
||||
|
||||
PR rtl-optimization/27735
|
||||
* cfgloopmanip.c (fix_loop_placements, fix_bb_placements, unloop):
|
||||
Add new argument to keep track of whether an irreducible region
|
||||
was affected. All callers changed.
|
||||
(fix_irreducible_loops): Removed.
|
||||
(remove_path): Call mark_irreducible_loops if EDGE_IRREDUCIBLE_LOOP
|
||||
flags were invalidated.
|
||||
|
||||
2006-08-29 H.J. Lu <hongjiu.lu@intel.com>
|
||||
|
||||
* config/i386/i386.md (*fop_df_comm_mixed): Match DF operands
|
||||
|
|
|
@ -41,14 +41,13 @@ static bool rpe_enum_p (basic_block, void *);
|
|||
static int find_path (edge, basic_block **);
|
||||
static bool alp_enum_p (basic_block, void *);
|
||||
static void add_loop (struct loops *, struct loop *);
|
||||
static void fix_loop_placements (struct loops *, struct loop *);
|
||||
static void fix_loop_placements (struct loops *, struct loop *, bool *);
|
||||
static bool fix_bb_placement (struct loops *, basic_block);
|
||||
static void fix_bb_placements (struct loops *, basic_block);
|
||||
static void fix_bb_placements (struct loops *, basic_block, bool *);
|
||||
static void place_new_loop (struct loops *, struct loop *);
|
||||
static void scale_loop_frequencies (struct loop *, int, int);
|
||||
static basic_block create_preheader (struct loop *, int);
|
||||
static void fix_irreducible_loops (basic_block);
|
||||
static void unloop (struct loops *, struct loop *);
|
||||
static void unloop (struct loops *, struct loop *, bool *);
|
||||
|
||||
#define RDIV(X,Y) (((X) + (Y) / 2) / (Y))
|
||||
|
||||
|
@ -133,9 +132,14 @@ fix_bb_placement (struct loops *loops, basic_block bb)
|
|||
its predecessors that may change if placement of FROM changed. Also fix
|
||||
placement of subloops of FROM->loop_father, that might also be altered due
|
||||
to this change; the condition for them is similar, except that instead of
|
||||
successors we consider edges coming out of the loops. */
|
||||
successors we consider edges coming out of the loops.
|
||||
|
||||
If the changes may invalidate the information about irreducible regions,
|
||||
IRRED_INVALIDATED is set to true. */
|
||||
|
||||
static void
|
||||
fix_bb_placements (struct loops *loops, basic_block from)
|
||||
fix_bb_placements (struct loops *loops, basic_block from,
|
||||
bool *irred_invalidated)
|
||||
{
|
||||
sbitmap in_queue;
|
||||
basic_block *queue, *qtop, *qbeg, *qend;
|
||||
|
@ -187,12 +191,21 @@ fix_bb_placements (struct loops *loops, basic_block from)
|
|||
continue;
|
||||
}
|
||||
|
||||
FOR_EACH_EDGE (e, ei, from->succs)
|
||||
{
|
||||
if (e->flags & EDGE_IRREDUCIBLE_LOOP)
|
||||
*irred_invalidated = true;
|
||||
}
|
||||
|
||||
/* Something has changed, insert predecessors into queue. */
|
||||
FOR_EACH_EDGE (e, ei, from->preds)
|
||||
{
|
||||
basic_block pred = e->src;
|
||||
struct loop *nca;
|
||||
|
||||
if (e->flags & EDGE_IRREDUCIBLE_LOOP)
|
||||
*irred_invalidated = true;
|
||||
|
||||
if (TEST_BIT (in_queue, pred->index))
|
||||
continue;
|
||||
|
||||
|
@ -225,76 +238,6 @@ fix_bb_placements (struct loops *loops, basic_block from)
|
|||
free (queue);
|
||||
}
|
||||
|
||||
/* Basic block from has lost one or more of its predecessors, so it might
|
||||
mo longer be part irreducible loop. Fix it and proceed recursively
|
||||
for its successors if needed. */
|
||||
static void
|
||||
fix_irreducible_loops (basic_block from)
|
||||
{
|
||||
basic_block bb;
|
||||
basic_block *stack;
|
||||
int stack_top;
|
||||
sbitmap on_stack;
|
||||
edge *edges, e;
|
||||
unsigned num_edges, i;
|
||||
|
||||
if (!(from->flags & BB_IRREDUCIBLE_LOOP))
|
||||
return;
|
||||
|
||||
on_stack = sbitmap_alloc (last_basic_block);
|
||||
sbitmap_zero (on_stack);
|
||||
SET_BIT (on_stack, from->index);
|
||||
stack = XNEWVEC (basic_block, from->loop_father->num_nodes);
|
||||
stack[0] = from;
|
||||
stack_top = 1;
|
||||
|
||||
while (stack_top)
|
||||
{
|
||||
edge_iterator ei;
|
||||
bb = stack[--stack_top];
|
||||
RESET_BIT (on_stack, bb->index);
|
||||
|
||||
FOR_EACH_EDGE (e, ei, bb->preds)
|
||||
if (e->flags & EDGE_IRREDUCIBLE_LOOP)
|
||||
break;
|
||||
if (e)
|
||||
continue;
|
||||
|
||||
bb->flags &= ~BB_IRREDUCIBLE_LOOP;
|
||||
if (bb->loop_father->header == bb)
|
||||
edges = get_loop_exit_edges (bb->loop_father, &num_edges);
|
||||
else
|
||||
{
|
||||
num_edges = EDGE_COUNT (bb->succs);
|
||||
edges = XNEWVEC (edge, num_edges);
|
||||
FOR_EACH_EDGE (e, ei, bb->succs)
|
||||
edges[ei.index] = e;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_edges; i++)
|
||||
{
|
||||
e = edges[i];
|
||||
|
||||
if (e->flags & EDGE_IRREDUCIBLE_LOOP)
|
||||
{
|
||||
if (!flow_bb_inside_loop_p (from->loop_father, e->dest))
|
||||
continue;
|
||||
|
||||
e->flags &= ~EDGE_IRREDUCIBLE_LOOP;
|
||||
if (TEST_BIT (on_stack, e->dest->index))
|
||||
continue;
|
||||
|
||||
SET_BIT (on_stack, e->dest->index);
|
||||
stack[stack_top++] = e->dest;
|
||||
}
|
||||
}
|
||||
free (edges);
|
||||
}
|
||||
|
||||
free (on_stack);
|
||||
free (stack);
|
||||
}
|
||||
|
||||
/* Removes path beginning at edge E, i.e. remove basic blocks dominated by E
|
||||
and update loop structure stored in LOOPS and dominators. Return true if
|
||||
we were able to remove the path, false otherwise (and nothing is affected
|
||||
|
@ -306,11 +249,19 @@ remove_path (struct loops *loops, edge e)
|
|||
basic_block *rem_bbs, *bord_bbs, *dom_bbs, from, bb;
|
||||
int i, nrem, n_bord_bbs, n_dom_bbs;
|
||||
sbitmap seen;
|
||||
bool deleted;
|
||||
bool deleted, irred_invalidated = false;
|
||||
|
||||
if (!loop_delete_branch_edge (e, 0))
|
||||
return false;
|
||||
|
||||
/* Keep track of whether we need to update information about irreducible
|
||||
regions. This is the case if the removed area is a part of the
|
||||
irreducible region, or if the set of basic blocks that belong to a loop
|
||||
that is inside an irreducible region is changed, or if such a loop is
|
||||
removed. */
|
||||
if (e->flags & EDGE_IRREDUCIBLE_LOOP)
|
||||
irred_invalidated = true;
|
||||
|
||||
/* We need to check whether basic blocks are dominated by the edge
|
||||
e, but we only have basic block dominators. This is easy to
|
||||
fix -- when e->dest has exactly one predecessor, this corresponds
|
||||
|
@ -325,7 +276,7 @@ remove_path (struct loops *loops, edge e)
|
|||
while (e->src->loop_father->outer
|
||||
&& dominated_by_p (CDI_DOMINATORS,
|
||||
e->src->loop_father->latch, e->dest))
|
||||
unloop (loops, e->src->loop_father);
|
||||
unloop (loops, e->src->loop_father, &irred_invalidated);
|
||||
|
||||
/* Identify the path. */
|
||||
nrem = find_path (e, &rem_bbs);
|
||||
|
@ -347,6 +298,9 @@ remove_path (struct loops *loops, edge e)
|
|||
{
|
||||
SET_BIT (seen, ae->dest->index);
|
||||
bord_bbs[n_bord_bbs++] = ae->dest;
|
||||
|
||||
if (ae->flags & EDGE_IRREDUCIBLE_LOOP)
|
||||
irred_invalidated = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -388,17 +342,16 @@ remove_path (struct loops *loops, edge e)
|
|||
/* Recount dominators. */
|
||||
iterate_fix_dominators (CDI_DOMINATORS, dom_bbs, n_dom_bbs);
|
||||
free (dom_bbs);
|
||||
|
||||
/* These blocks have lost some predecessor(s), thus their irreducible
|
||||
status could be changed. */
|
||||
for (i = 0; i < n_bord_bbs; i++)
|
||||
fix_irreducible_loops (bord_bbs[i]);
|
||||
free (bord_bbs);
|
||||
|
||||
/* Fix placements of basic blocks inside loops and the placement of
|
||||
loops in the loop tree. */
|
||||
fix_bb_placements (loops, from);
|
||||
fix_loop_placements (loops, from->loop_father);
|
||||
fix_bb_placements (loops, from, &irred_invalidated);
|
||||
fix_loop_placements (loops, from->loop_father, &irred_invalidated);
|
||||
|
||||
if (irred_invalidated
|
||||
&& (loops->state & LOOPS_HAVE_MARKED_IRREDUCIBLE_REGIONS) != 0)
|
||||
mark_irreducible_loops (loops);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -549,16 +502,22 @@ loopify (struct loops *loops, edge latch_edge, edge header_edge,
|
|||
|
||||
/* Remove the latch edge of a LOOP and update LOOPS tree to indicate that
|
||||
the LOOP was removed. After this function, original loop latch will
|
||||
have no successor, which caller is expected to fix somehow. */
|
||||
have no successor, which caller is expected to fix somehow.
|
||||
|
||||
If this may cause the information about irreducible regions to become
|
||||
invalid, IRRED_INVALIDATED is set to true. */
|
||||
|
||||
static void
|
||||
unloop (struct loops *loops, struct loop *loop)
|
||||
unloop (struct loops *loops, struct loop *loop, bool *irred_invalidated)
|
||||
{
|
||||
basic_block *body;
|
||||
struct loop *ploop;
|
||||
unsigned i, n;
|
||||
basic_block latch = loop->latch;
|
||||
edge *edges;
|
||||
unsigned num_edges;
|
||||
bool dummy = false;
|
||||
|
||||
if (loop_preheader_edge (loop)->flags & EDGE_IRREDUCIBLE_LOOP)
|
||||
*irred_invalidated = true;
|
||||
|
||||
/* This is relatively straightforward. The dominators are unchanged, as
|
||||
loop header dominates loop latch, so the only thing we have to care of
|
||||
|
@ -567,7 +526,6 @@ unloop (struct loops *loops, struct loop *loop)
|
|||
its work. */
|
||||
|
||||
body = get_loop_body (loop);
|
||||
edges = get_loop_exit_edges (loop, &num_edges);
|
||||
n = loop->num_nodes;
|
||||
for (i = 0; i < n; i++)
|
||||
if (body[i]->loop_father == loop)
|
||||
|
@ -590,24 +548,18 @@ unloop (struct loops *loops, struct loop *loop)
|
|||
flow_loop_free (loop);
|
||||
|
||||
remove_edge (single_succ_edge (latch));
|
||||
fix_bb_placements (loops, latch);
|
||||
|
||||
/* If the loop was inside an irreducible region, we would have to somehow
|
||||
update the irreducible marks inside its body. While it is certainly
|
||||
possible to do, it is a bit complicated and this situation should be
|
||||
very rare, so we just remark all loops in this case. */
|
||||
for (i = 0; i < num_edges; i++)
|
||||
if (edges[i]->flags & EDGE_IRREDUCIBLE_LOOP)
|
||||
break;
|
||||
if (i != num_edges)
|
||||
mark_irreducible_loops (loops);
|
||||
free (edges);
|
||||
/* We do not pass IRRED_INVALIDATED to fix_bb_placements here, as even if
|
||||
there is an irreducible region inside the cancelled loop, the flags will
|
||||
be still correct. */
|
||||
fix_bb_placements (loops, latch, &dummy);
|
||||
}
|
||||
|
||||
/* Fix placement of LOOP inside loop tree, i.e. find the innermost superloop
|
||||
FATHER of LOOP such that all of the edges coming out of LOOP belong to
|
||||
FATHER, and set it as outer loop of LOOP. Return 1 if placement of
|
||||
FATHER, and set it as outer loop of LOOP. Return true if placement of
|
||||
LOOP changed. */
|
||||
|
||||
int
|
||||
fix_loop_placement (struct loop *loop)
|
||||
{
|
||||
|
@ -642,9 +594,14 @@ fix_loop_placement (struct loop *loop)
|
|||
/* Fix placement of superloops of LOOP inside loop tree, i.e. ensure that
|
||||
condition stated in description of fix_loop_placement holds for them.
|
||||
It is used in case when we removed some edges coming out of LOOP, which
|
||||
may cause the right placement of LOOP inside loop tree to change. */
|
||||
may cause the right placement of LOOP inside loop tree to change.
|
||||
|
||||
IRRED_INVALIDATED is set to true if a change in the loop structures might
|
||||
invalidate the information about irreducible regions. */
|
||||
|
||||
static void
|
||||
fix_loop_placements (struct loops *loops, struct loop *loop)
|
||||
fix_loop_placements (struct loops *loops, struct loop *loop,
|
||||
bool *irred_invalidated)
|
||||
{
|
||||
struct loop *outer;
|
||||
|
||||
|
@ -659,7 +616,8 @@ fix_loop_placements (struct loops *loops, struct loop *loop)
|
|||
for its preheader, because the successor is the header and belongs
|
||||
to the loop. So call fix_bb_placements to fix up the placement
|
||||
of the preheader and (possibly) of its predecessors. */
|
||||
fix_bb_placements (loops, loop_preheader_edge (loop)->src);
|
||||
fix_bb_placements (loops, loop_preheader_edge (loop)->src,
|
||||
irred_invalidated);
|
||||
loop = outer;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
2006-08-30 Zdenek Dvorak <dvorakz@suse.cz>
|
||||
|
||||
PR rtl-optimization/27735
|
||||
* gcc.dg/loop-unswitch-1.c: New test.
|
||||
|
||||
2006-08-30 Paul Thomas <pault@gcc.gnu.org>
|
||||
|
||||
PR fortran/28885
|
||||
|
|
34
gcc/testsuite/gcc.dg/loop-unswitch-1.c
Normal file
34
gcc/testsuite/gcc.dg/loop-unswitch-1.c
Normal file
|
@ -0,0 +1,34 @@
|
|||
/* For PR rtl-optimization/27735 */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -funswitch-loops" } */
|
||||
|
||||
void set_color(void);
|
||||
void xml_colorize_line(unsigned int *p, int state)
|
||||
{
|
||||
int c;
|
||||
switch(state)
|
||||
{
|
||||
case 1:
|
||||
goto parse_tag;
|
||||
case 2:
|
||||
goto parse_comment;
|
||||
}
|
||||
|
||||
for(;;)
|
||||
{
|
||||
c = *p;
|
||||
if (c == '<' && state == 0)
|
||||
{
|
||||
parse_comment: ;
|
||||
while (*p != '\n')
|
||||
state = 3;
|
||||
parse_tag: ;
|
||||
while (*p != '\n')
|
||||
state = 0;
|
||||
set_color();
|
||||
}
|
||||
else
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
Loading…
Add table
Reference in a new issue