loop.texi: Document recording of loop exits.
* doc/loop.texi: Document recording of loop exits. * cfgloopmanip.c (loopify, duplicate_loop): Use alloc_loop. (update_single_exits_after_duplication, update_single_exit_for_duplicated_loop, update_single_exit_for_duplicated_loops): Removed. (duplicate_loop_to_header_edge): Do not call update_single_exits_after_duplication and update_single_exit_for_duplicated_loops. (loop_version): Do not update single_exit information. (fix_loop_structure): Use record_loop_exits instead of mark_single_exit_loops. * tree-ssa-loop-manip.c (tree_transform_and_unroll_loop): Update the lists of loop exits. * cfghooks.c (redirect_edge_and_branch, redirect_edge_and_branch_force, split_edge, merge_blocks): Update the lists of loop exits. * modulo-sched.c (sms_schedule): Pass LOOPS_HAVE_RECORDED_EXITS to loop_optimizer_init. * loop-init.c (loop_optimizer_init): Call record_loop_exits instead of mark_single_exit_loops. (loop_optimizer_finalize): Call release_recorded_exits. * tree-ssa-loop.c (tree_loop_optimizer_init): Pass LOOPS_HAVE_RECORDED_EXITS to loop_optimizer_init. * tree-vectorizer.c (slpeel_tree_duplicate_loop_to_edge_cfg): Do not update single exit information. * lambda-code.c (perfect_nestify): Ditto. * cfgloop.c (flow_loop_free): Destroy the list of exits of the loop. (mark_single_exit_loops): Removed. (alloc_loop, loop_exit_hash, loop_exit_eq, loop_exit_free, get_exit_descriptions, rescan_loop_exit, record_loop_exits, dump_recorded_exit, dump_recorded_exits, release_recorded_exits): New functions. (get_loop_exit_edges, single_exit): Use recorded exit lists. (add_bb_to_loop, remove_bb_from_loops): Update the lists of loop exits. (verify_loop_structure): Verify consistency of the exit lists. (flow_loops_find): Use alloc_loop. Initialize exits hash. (set_single_exit): Removed. * cfgloop.h (struct loop_exit): New function. (struct loop): single_exit_ field replaced by exits field. (LOOPS_HAVE_MARKED_SINGLE_EXITS): Replaced by LOOPS_HAVE_RECORDED_EXITS. (struct loops): Added exits hash. (mark_single_exit_loops, set_single_exit): Declaration removed. (release_recorded_exits, record_loop_exits, rescan_loop_exit): Declare. From-SVN: r120728
This commit is contained in:
parent
1cbe999f08
commit
6270df4c21
|
@ -1,3 +1,48 @@
|
|||
2007-01-12 Zdenek Dvorak <dvorakz@suse.cz>
|
||||
|
||||
* doc/loop.texi: Document recording of loop exits.
|
||||
* cfgloopmanip.c (loopify, duplicate_loop): Use alloc_loop.
|
||||
(update_single_exits_after_duplication,
|
||||
update_single_exit_for_duplicated_loop,
|
||||
update_single_exit_for_duplicated_loops): Removed.
|
||||
(duplicate_loop_to_header_edge): Do not call
|
||||
update_single_exits_after_duplication and
|
||||
update_single_exit_for_duplicated_loops.
|
||||
(loop_version): Do not update single_exit information.
|
||||
(fix_loop_structure): Use record_loop_exits instead of
|
||||
mark_single_exit_loops.
|
||||
* tree-ssa-loop-manip.c (tree_transform_and_unroll_loop): Update
|
||||
the lists of loop exits.
|
||||
* cfghooks.c (redirect_edge_and_branch, redirect_edge_and_branch_force,
|
||||
split_edge, merge_blocks): Update the lists of loop exits.
|
||||
* modulo-sched.c (sms_schedule): Pass LOOPS_HAVE_RECORDED_EXITS to
|
||||
loop_optimizer_init.
|
||||
* loop-init.c (loop_optimizer_init): Call record_loop_exits instead
|
||||
of mark_single_exit_loops.
|
||||
(loop_optimizer_finalize): Call release_recorded_exits.
|
||||
* tree-ssa-loop.c (tree_loop_optimizer_init): Pass
|
||||
LOOPS_HAVE_RECORDED_EXITS to loop_optimizer_init.
|
||||
* tree-vectorizer.c (slpeel_tree_duplicate_loop_to_edge_cfg): Do not
|
||||
update single exit information.
|
||||
* lambda-code.c (perfect_nestify): Ditto.
|
||||
* cfgloop.c (flow_loop_free): Destroy the list of exits of the loop.
|
||||
(mark_single_exit_loops): Removed.
|
||||
(alloc_loop, loop_exit_hash, loop_exit_eq, loop_exit_free,
|
||||
get_exit_descriptions, rescan_loop_exit, record_loop_exits,
|
||||
dump_recorded_exit, dump_recorded_exits, release_recorded_exits): New
|
||||
functions.
|
||||
(get_loop_exit_edges, single_exit): Use recorded exit lists.
|
||||
(add_bb_to_loop, remove_bb_from_loops): Update the lists of loop exits.
|
||||
(verify_loop_structure): Verify consistency of the exit lists.
|
||||
(flow_loops_find): Use alloc_loop. Initialize exits hash.
|
||||
(set_single_exit): Removed.
|
||||
* cfgloop.h (struct loop_exit): New function.
|
||||
(struct loop): single_exit_ field replaced by exits field.
|
||||
(LOOPS_HAVE_MARKED_SINGLE_EXITS): Replaced by LOOPS_HAVE_RECORDED_EXITS.
|
||||
(struct loops): Added exits hash.
|
||||
(mark_single_exit_loops, set_single_exit): Declaration removed.
|
||||
(release_recorded_exits, record_loop_exits, rescan_loop_exit): Declare.
|
||||
|
||||
2007-01-12 Richard Sandiford <richard@codesourcery.com>
|
||||
|
||||
* doc/invoke.texi: Avoid use of @headitem.
|
||||
|
|
|
@ -310,6 +310,11 @@ redirect_edge_and_branch (edge e, basic_block dest)
|
|||
|
||||
ret = cfg_hooks->redirect_edge_and_branch (e, dest);
|
||||
|
||||
/* If RET != E, then the edge E was removed since RET already lead to the
|
||||
same destination. */
|
||||
if (ret != NULL && current_loops != NULL)
|
||||
rescan_loop_exit (e, false, ret != e);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -320,19 +325,27 @@ redirect_edge_and_branch (edge e, basic_block dest)
|
|||
basic_block
|
||||
redirect_edge_and_branch_force (edge e, basic_block dest)
|
||||
{
|
||||
basic_block ret;
|
||||
basic_block ret, src = e->src;
|
||||
struct loop *loop;
|
||||
|
||||
if (!cfg_hooks->redirect_edge_and_branch_force)
|
||||
internal_error ("%s does not support redirect_edge_and_branch_force",
|
||||
cfg_hooks->name);
|
||||
|
||||
if (current_loops != NULL)
|
||||
rescan_loop_exit (e, false, true);
|
||||
|
||||
ret = cfg_hooks->redirect_edge_and_branch_force (e, dest);
|
||||
if (current_loops != NULL && ret != NULL)
|
||||
if (current_loops != NULL)
|
||||
{
|
||||
loop = find_common_loop (single_pred (ret)->loop_father,
|
||||
single_succ (ret)->loop_father);
|
||||
add_bb_to_loop (ret, loop);
|
||||
if (ret != NULL)
|
||||
{
|
||||
loop = find_common_loop (single_pred (ret)->loop_father,
|
||||
single_succ (ret)->loop_father);
|
||||
add_bb_to_loop (ret, loop);
|
||||
}
|
||||
else if (find_edge (src, dest) == e)
|
||||
rescan_loop_exit (e, true, false);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -452,6 +465,9 @@ split_edge (edge e)
|
|||
if (!cfg_hooks->split_edge)
|
||||
internal_error ("%s does not support split_edge", cfg_hooks->name);
|
||||
|
||||
if (current_loops != NULL)
|
||||
rescan_loop_exit (e, false, true);
|
||||
|
||||
ret = cfg_hooks->split_edge (e);
|
||||
ret->count = count;
|
||||
ret->frequency = freq;
|
||||
|
@ -595,11 +611,19 @@ merge_blocks (basic_block a, basic_block b)
|
|||
whole lot of them and hope the caller knows what they're doing. */
|
||||
|
||||
while (EDGE_COUNT (a->succs) != 0)
|
||||
remove_edge (EDGE_SUCC (a, 0));
|
||||
{
|
||||
if (current_loops != NULL)
|
||||
rescan_loop_exit (EDGE_SUCC (a, 0), false, true);
|
||||
remove_edge (EDGE_SUCC (a, 0));
|
||||
}
|
||||
|
||||
/* Adjust the edges out of B for the new owner. */
|
||||
FOR_EACH_EDGE (e, ei, b->succs)
|
||||
e->src = a;
|
||||
{
|
||||
e->src = a;
|
||||
if (current_loops != NULL)
|
||||
rescan_loop_exit (e, true, false);
|
||||
}
|
||||
a->succs = b->succs;
|
||||
a->flags |= b->flags;
|
||||
|
||||
|
|
456
gcc/cfgloop.c
456
gcc/cfgloop.c
|
@ -149,8 +149,22 @@ flow_loops_dump (FILE *file, void (*loop_dump_aux) (const struct loop *, FILE *,
|
|||
void
|
||||
flow_loop_free (struct loop *loop)
|
||||
{
|
||||
struct loop_exit *exit, *next;
|
||||
|
||||
if (loop->pred)
|
||||
free (loop->pred);
|
||||
|
||||
/* Break the list of the loop exit records. They will be freed when the
|
||||
corresponding edge is rescanned or removed, and this avoids
|
||||
accessing the (already released) head of the list stored in the
|
||||
loop structure. */
|
||||
for (exit = loop->exits.next; exit != &loop->exits; exit = next)
|
||||
{
|
||||
next = exit->next;
|
||||
exit->next = exit;
|
||||
exit->prev = exit;
|
||||
}
|
||||
|
||||
free (loop);
|
||||
}
|
||||
|
||||
|
@ -227,57 +241,6 @@ flow_loop_nodes_find (basic_block header, struct loop *loop)
|
|||
return num_nodes;
|
||||
}
|
||||
|
||||
/* For each loop that has just a single exit, record the exit edge. */
|
||||
|
||||
void
|
||||
mark_single_exit_loops (void)
|
||||
{
|
||||
basic_block bb;
|
||||
edge e;
|
||||
struct loop *loop;
|
||||
loop_iterator li;
|
||||
|
||||
FOR_EACH_LOOP (li, loop, 0)
|
||||
{
|
||||
set_single_exit (loop, NULL);
|
||||
}
|
||||
|
||||
FOR_EACH_BB (bb)
|
||||
{
|
||||
edge_iterator ei;
|
||||
if (bb->loop_father == current_loops->tree_root)
|
||||
continue;
|
||||
FOR_EACH_EDGE (e, ei, bb->succs)
|
||||
{
|
||||
if (e->dest == EXIT_BLOCK_PTR)
|
||||
continue;
|
||||
|
||||
if (flow_bb_inside_loop_p (bb->loop_father, e->dest))
|
||||
continue;
|
||||
|
||||
for (loop = bb->loop_father;
|
||||
loop != e->dest->loop_father;
|
||||
loop = loop->outer)
|
||||
{
|
||||
/* If we have already seen an exit, mark this by the edge that
|
||||
surely does not occur as any exit. */
|
||||
if (single_exit (loop))
|
||||
set_single_exit (loop, single_succ_edge (ENTRY_BLOCK_PTR));
|
||||
else
|
||||
set_single_exit (loop, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FOR_EACH_LOOP (li, loop, 0)
|
||||
{
|
||||
if (single_exit (loop) == single_succ_edge (ENTRY_BLOCK_PTR))
|
||||
set_single_exit (loop, NULL);
|
||||
}
|
||||
|
||||
current_loops->state |= LOOPS_HAVE_MARKED_SINGLE_EXITS;
|
||||
}
|
||||
|
||||
static void
|
||||
establish_preds (struct loop *loop)
|
||||
{
|
||||
|
@ -486,6 +449,17 @@ canonicalize_loop_headers (void)
|
|||
#endif
|
||||
}
|
||||
|
||||
/* Allocates and returns new loop structure. */
|
||||
|
||||
struct loop *
|
||||
alloc_loop (void)
|
||||
{
|
||||
struct loop *loop = XCNEW (struct loop);
|
||||
|
||||
loop->exits.next = loop->exits.prev = &loop->exits;
|
||||
return loop;
|
||||
}
|
||||
|
||||
/* Find all the natural loops in the function and save in LOOPS structure and
|
||||
recalculate loop_depth information in basic block structures.
|
||||
Return the number of natural loops found. */
|
||||
|
@ -571,7 +545,7 @@ flow_loops_find (struct loops *loops)
|
|||
loops->larray = VEC_alloc (loop_p, heap, num_loops + 1);
|
||||
|
||||
/* Dummy loop containing whole function. */
|
||||
root = XCNEW (struct loop);
|
||||
root = alloc_loop ();
|
||||
root->num_nodes = n_basic_blocks;
|
||||
root->latch = EXIT_BLOCK_PTR;
|
||||
root->header = ENTRY_BLOCK_PTR;
|
||||
|
@ -608,7 +582,7 @@ flow_loops_find (struct loops *loops)
|
|||
|
||||
header = BASIC_BLOCK (rc_order[b]);
|
||||
|
||||
loop = XCNEW (struct loop);
|
||||
loop = alloc_loop ();
|
||||
VEC_quick_push (loop_p, loops->larray, loop);
|
||||
|
||||
loop->header = header;
|
||||
|
@ -638,6 +612,7 @@ flow_loops_find (struct loops *loops)
|
|||
|
||||
sbitmap_free (headers);
|
||||
|
||||
loops->exits = NULL;
|
||||
loops->state = 0;
|
||||
return VEC_length (loop_p, loops->larray);
|
||||
}
|
||||
|
@ -799,6 +774,181 @@ get_loop_body_in_bfs_order (const struct loop *loop)
|
|||
return blocks;
|
||||
}
|
||||
|
||||
/* Hash function for struct loop_exit. */
|
||||
|
||||
static hashval_t
|
||||
loop_exit_hash (const void *ex)
|
||||
{
|
||||
struct loop_exit *exit = (struct loop_exit *) ex;
|
||||
|
||||
return htab_hash_pointer (exit->e);
|
||||
}
|
||||
|
||||
/* Equality function for struct loop_exit. Compares with edge. */
|
||||
|
||||
static int
|
||||
loop_exit_eq (const void *ex, const void *e)
|
||||
{
|
||||
struct loop_exit *exit = (struct loop_exit *) ex;
|
||||
|
||||
return exit->e == e;
|
||||
}
|
||||
|
||||
/* Frees the list of loop exit descriptions EX. */
|
||||
|
||||
static void
|
||||
loop_exit_free (void *ex)
|
||||
{
|
||||
struct loop_exit *exit = (struct loop_exit *) ex, *next;
|
||||
|
||||
for (; exit; exit = next)
|
||||
{
|
||||
next = exit->next_e;
|
||||
|
||||
exit->next->prev = exit->prev;
|
||||
exit->prev->next = exit->next;
|
||||
|
||||
free (exit);
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns the list of records for E as an exit of a loop. */
|
||||
|
||||
static struct loop_exit *
|
||||
get_exit_descriptions (edge e)
|
||||
{
|
||||
return htab_find_with_hash (current_loops->exits, e,
|
||||
htab_hash_pointer (e));
|
||||
}
|
||||
|
||||
/* Updates the lists of loop exits in that E appears.
|
||||
If REMOVED is true, E is being removed, and we
|
||||
just remove it from the lists of exits.
|
||||
If NEW_EDGE is true and E is not a loop exit, we
|
||||
do not try to remove it from loop exit lists. */
|
||||
|
||||
void
|
||||
rescan_loop_exit (edge e, bool new_edge, bool removed)
|
||||
{
|
||||
void **slot;
|
||||
struct loop_exit *exits = NULL, *exit;
|
||||
struct loop *aloop, *cloop;
|
||||
|
||||
if ((current_loops->state & LOOPS_HAVE_RECORDED_EXITS) == 0)
|
||||
return;
|
||||
|
||||
if (!removed
|
||||
&& e->src->loop_father != NULL
|
||||
&& e->dest->loop_father != NULL
|
||||
&& !flow_bb_inside_loop_p (e->src->loop_father, e->dest))
|
||||
{
|
||||
cloop = find_common_loop (e->src->loop_father, e->dest->loop_father);
|
||||
for (aloop = e->src->loop_father;
|
||||
aloop != cloop;
|
||||
aloop = aloop->outer)
|
||||
{
|
||||
exit = XNEW (struct loop_exit);
|
||||
exit->e = e;
|
||||
|
||||
exit->next = aloop->exits.next;
|
||||
exit->prev = &aloop->exits;
|
||||
exit->next->prev = exit;
|
||||
exit->prev->next = exit;
|
||||
|
||||
exit->next_e = exits;
|
||||
exits = exit;
|
||||
}
|
||||
}
|
||||
|
||||
if (!exits && new_edge)
|
||||
return;
|
||||
|
||||
slot = htab_find_slot_with_hash (current_loops->exits, e,
|
||||
htab_hash_pointer (e),
|
||||
exits ? INSERT : NO_INSERT);
|
||||
if (!slot)
|
||||
return;
|
||||
|
||||
if (exits)
|
||||
{
|
||||
if (*slot)
|
||||
loop_exit_free (*slot);
|
||||
*slot = exits;
|
||||
}
|
||||
else
|
||||
htab_clear_slot (current_loops->exits, slot);
|
||||
}
|
||||
|
||||
/* For each loop, record list of exit edges, and start maintaining these
|
||||
lists. */
|
||||
|
||||
void
|
||||
record_loop_exits (void)
|
||||
{
|
||||
basic_block bb;
|
||||
edge_iterator ei;
|
||||
edge e;
|
||||
|
||||
if (current_loops->state & LOOPS_HAVE_RECORDED_EXITS)
|
||||
return;
|
||||
current_loops->state |= LOOPS_HAVE_RECORDED_EXITS;
|
||||
|
||||
gcc_assert (current_loops->exits == NULL);
|
||||
current_loops->exits = htab_create (2 * number_of_loops (),
|
||||
loop_exit_hash,
|
||||
loop_exit_eq,
|
||||
loop_exit_free);
|
||||
|
||||
FOR_EACH_BB (bb)
|
||||
{
|
||||
FOR_EACH_EDGE (e, ei, bb->succs)
|
||||
{
|
||||
rescan_loop_exit (e, true, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Dumps information about the exit in *SLOT to FILE.
|
||||
Callback for htab_traverse. */
|
||||
|
||||
static int
|
||||
dump_recorded_exit (void **slot, void *file)
|
||||
{
|
||||
struct loop_exit *exit = *slot;
|
||||
unsigned n = 0;
|
||||
edge e = exit->e;
|
||||
|
||||
for (; exit != NULL; exit = exit->next_e)
|
||||
n++;
|
||||
|
||||
fprintf (file, "Edge %d->%d exits %u loops\n",
|
||||
e->src->index, e->dest->index, n);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Dumps the recorded exits of loops to FILE. */
|
||||
|
||||
extern void dump_recorded_exits (FILE *);
|
||||
void
|
||||
dump_recorded_exits (FILE *file)
|
||||
{
|
||||
if (!current_loops->exits)
|
||||
return;
|
||||
htab_traverse (current_loops->exits, dump_recorded_exit, file);
|
||||
}
|
||||
|
||||
/* Releases lists of loop exits. */
|
||||
|
||||
void
|
||||
release_recorded_exits (void)
|
||||
{
|
||||
gcc_assert (current_loops->state & LOOPS_HAVE_RECORDED_EXITS);
|
||||
htab_delete (current_loops->exits);
|
||||
current_loops->exits = NULL;
|
||||
current_loops->state &= ~LOOPS_HAVE_RECORDED_EXITS;
|
||||
}
|
||||
|
||||
/* Returns the list of the exit edges of a LOOP. */
|
||||
|
||||
VEC (edge, heap) *
|
||||
|
@ -809,15 +959,28 @@ get_loop_exit_edges (const struct loop *loop)
|
|||
unsigned i;
|
||||
basic_block *body;
|
||||
edge_iterator ei;
|
||||
struct loop_exit *exit;
|
||||
|
||||
gcc_assert (loop->latch != EXIT_BLOCK_PTR);
|
||||
|
||||
body = get_loop_body (loop);
|
||||
for (i = 0; i < loop->num_nodes; i++)
|
||||
FOR_EACH_EDGE (e, ei, body[i]->succs)
|
||||
if (!flow_bb_inside_loop_p (loop, e->dest))
|
||||
VEC_safe_push (edge, heap, edges, e);
|
||||
free (body);
|
||||
/* If we maintain the lists of exits, use them. Otherwise we must
|
||||
scan the body of the loop. */
|
||||
if (current_loops->state & LOOPS_HAVE_RECORDED_EXITS)
|
||||
{
|
||||
for (exit = loop->exits.next; exit->e; exit = exit->next)
|
||||
VEC_safe_push (edge, heap, edges, exit->e);
|
||||
}
|
||||
else
|
||||
{
|
||||
body = get_loop_body (loop);
|
||||
for (i = 0; i < loop->num_nodes; i++)
|
||||
FOR_EACH_EDGE (e, ei, body[i]->succs)
|
||||
{
|
||||
if (!flow_bb_inside_loop_p (loop, e->dest))
|
||||
VEC_safe_push (edge, heap, edges, e);
|
||||
}
|
||||
free (body);
|
||||
}
|
||||
|
||||
return edges;
|
||||
}
|
||||
|
@ -846,29 +1009,51 @@ num_loop_branches (const struct loop *loop)
|
|||
void
|
||||
add_bb_to_loop (basic_block bb, struct loop *loop)
|
||||
{
|
||||
int i;
|
||||
int i;
|
||||
edge_iterator ei;
|
||||
edge e;
|
||||
|
||||
gcc_assert (bb->loop_father == NULL);
|
||||
bb->loop_father = loop;
|
||||
bb->loop_depth = loop->depth;
|
||||
loop->num_nodes++;
|
||||
for (i = 0; i < loop->depth; i++)
|
||||
loop->pred[i]->num_nodes++;
|
||||
gcc_assert (bb->loop_father == NULL);
|
||||
bb->loop_father = loop;
|
||||
bb->loop_depth = loop->depth;
|
||||
loop->num_nodes++;
|
||||
for (i = 0; i < loop->depth; i++)
|
||||
loop->pred[i]->num_nodes++;
|
||||
|
||||
FOR_EACH_EDGE (e, ei, bb->succs)
|
||||
{
|
||||
rescan_loop_exit (e, true, false);
|
||||
}
|
||||
FOR_EACH_EDGE (e, ei, bb->preds)
|
||||
{
|
||||
rescan_loop_exit (e, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove basic block BB from loops. */
|
||||
void
|
||||
remove_bb_from_loops (basic_block bb)
|
||||
{
|
||||
int i;
|
||||
struct loop *loop = bb->loop_father;
|
||||
int i;
|
||||
struct loop *loop = bb->loop_father;
|
||||
edge_iterator ei;
|
||||
edge e;
|
||||
|
||||
gcc_assert (loop != NULL);
|
||||
loop->num_nodes--;
|
||||
for (i = 0; i < loop->depth; i++)
|
||||
loop->pred[i]->num_nodes--;
|
||||
bb->loop_father = NULL;
|
||||
bb->loop_depth = 0;
|
||||
gcc_assert (loop != NULL);
|
||||
loop->num_nodes--;
|
||||
for (i = 0; i < loop->depth; i++)
|
||||
loop->pred[i]->num_nodes--;
|
||||
bb->loop_father = NULL;
|
||||
bb->loop_depth = 0;
|
||||
|
||||
FOR_EACH_EDGE (e, ei, bb->succs)
|
||||
{
|
||||
rescan_loop_exit (e, false, true);
|
||||
}
|
||||
FOR_EACH_EDGE (e, ei, bb->preds)
|
||||
{
|
||||
rescan_loop_exit (e, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
/* Finds nearest common ancestor in loop tree for given loops. */
|
||||
|
@ -951,6 +1136,7 @@ verify_loop_structure (void)
|
|||
edge e;
|
||||
unsigned num = number_of_loops ();
|
||||
loop_iterator li;
|
||||
struct loop_exit *exit, *mexit;
|
||||
|
||||
/* Check sizes. */
|
||||
sizes = XCNEWVEC (unsigned, num);
|
||||
|
@ -1088,9 +1274,49 @@ verify_loop_structure (void)
|
|||
free (irreds);
|
||||
}
|
||||
|
||||
/* Check the single_exit. */
|
||||
if (current_loops->state & LOOPS_HAVE_MARKED_SINGLE_EXITS)
|
||||
/* Check the recorded loop exits. */
|
||||
FOR_EACH_LOOP (li, loop, 0)
|
||||
{
|
||||
if (loop->exits.e != NULL)
|
||||
{
|
||||
error ("corrupted head of the exits list of loop %d",
|
||||
loop->num);
|
||||
err = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Check that the list forms a cycle, and all elements except
|
||||
for the head are nonnull. */
|
||||
for (mexit = &loop->exits, exit = mexit->next, i = 0;
|
||||
exit->e && exit != mexit;
|
||||
exit = exit->next)
|
||||
{
|
||||
if (i++ & 1)
|
||||
mexit = mexit->next;
|
||||
}
|
||||
|
||||
if (exit != &loop->exits)
|
||||
{
|
||||
error ("corrupted exits list of loop %d", loop->num);
|
||||
err = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ((current_loops->state & LOOPS_HAVE_RECORDED_EXITS) == 0)
|
||||
{
|
||||
if (loop->exits.next != &loop->exits)
|
||||
{
|
||||
error ("nonempty exits list of loop %d, but exits are not recorded",
|
||||
loop->num);
|
||||
err = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (current_loops->state & LOOPS_HAVE_RECORDED_EXITS)
|
||||
{
|
||||
unsigned n_exits = 0, eloops;
|
||||
|
||||
memset (sizes, 0, sizeof (unsigned) * num);
|
||||
FOR_EACH_BB (bb)
|
||||
{
|
||||
|
@ -1099,50 +1325,53 @@ verify_loop_structure (void)
|
|||
continue;
|
||||
FOR_EACH_EDGE (e, ei, bb->succs)
|
||||
{
|
||||
if (e->dest == EXIT_BLOCK_PTR)
|
||||
continue;
|
||||
|
||||
if (flow_bb_inside_loop_p (bb->loop_father, e->dest))
|
||||
continue;
|
||||
|
||||
n_exits++;
|
||||
exit = get_exit_descriptions (e);
|
||||
if (!exit)
|
||||
{
|
||||
error ("Exit %d->%d not recorded",
|
||||
e->src->index, e->dest->index);
|
||||
err = 1;
|
||||
}
|
||||
eloops = 0;
|
||||
for (; exit; exit = exit->next_e)
|
||||
eloops++;
|
||||
|
||||
for (loop = bb->loop_father;
|
||||
loop != e->dest->loop_father;
|
||||
loop = loop->outer)
|
||||
{
|
||||
eloops--;
|
||||
sizes[loop->num]++;
|
||||
if (single_exit (loop)
|
||||
&& single_exit (loop) != e)
|
||||
{
|
||||
error ("wrong single exit %d->%d recorded for loop %d",
|
||||
single_exit (loop)->src->index,
|
||||
single_exit (loop)->dest->index,
|
||||
loop->num);
|
||||
error ("right exit is %d->%d",
|
||||
e->src->index, e->dest->index);
|
||||
err = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (eloops != 0)
|
||||
{
|
||||
error ("Wrong list of exited loops for edge %d->%d",
|
||||
e->src->index, e->dest->index);
|
||||
err = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (n_exits != htab_elements (current_loops->exits))
|
||||
{
|
||||
error ("Too many loop exits recorded");
|
||||
err = 1;
|
||||
}
|
||||
|
||||
FOR_EACH_LOOP (li, loop, 0)
|
||||
{
|
||||
i = loop->num;
|
||||
|
||||
if (sizes[i] == 1
|
||||
&& !single_exit (loop))
|
||||
eloops = 0;
|
||||
for (exit = loop->exits.next; exit->e; exit = exit->next)
|
||||
eloops++;
|
||||
if (eloops != sizes[loop->num])
|
||||
{
|
||||
error ("single exit not recorded for loop %d", loop->num);
|
||||
err = 1;
|
||||
}
|
||||
|
||||
if (sizes[i] != 1
|
||||
&& single_exit (loop))
|
||||
{
|
||||
error ("loop %d should not have single exit (%d -> %d)",
|
||||
loop->num,
|
||||
single_exit (loop)->src->index,
|
||||
single_exit (loop)->dest->index);
|
||||
error ("%d exits recorded for loop %d (having %d exits)",
|
||||
eloops, loop->num, sizes[loop->num]);
|
||||
err = 1;
|
||||
}
|
||||
}
|
||||
|
@ -1184,18 +1413,19 @@ loop_exit_edge_p (const struct loop *loop, edge e)
|
|||
}
|
||||
|
||||
/* Returns the single exit edge of LOOP, or NULL if LOOP has either no exit
|
||||
or more than one exit. */
|
||||
or more than one exit. If loops do not have the exits recorded, NULL
|
||||
is returned always. */
|
||||
|
||||
edge
|
||||
single_exit (const struct loop *loop)
|
||||
{
|
||||
return loop->single_exit_;
|
||||
}
|
||||
struct loop_exit *exit = loop->exits.next;
|
||||
|
||||
/* Records E as a single exit edge of LOOP. */
|
||||
if ((current_loops->state & LOOPS_HAVE_RECORDED_EXITS) == 0)
|
||||
return NULL;
|
||||
|
||||
void
|
||||
set_single_exit (struct loop *loop, edge e)
|
||||
{
|
||||
loop->single_exit_ = e;
|
||||
if (exit->e && exit->next == &loop->exits)
|
||||
return exit->e;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -74,6 +74,21 @@ struct nb_iter_bound
|
|||
struct nb_iter_bound *next;
|
||||
};
|
||||
|
||||
/* Description of the loop exit. */
|
||||
|
||||
struct loop_exit
|
||||
{
|
||||
/* The exit edge. */
|
||||
edge e;
|
||||
|
||||
/* Previous and next exit in the list of the exits of the loop. */
|
||||
struct loop_exit *prev;
|
||||
struct loop_exit *next;
|
||||
|
||||
/* Next element in the list of loops from that E exits. */
|
||||
struct loop_exit *next_e;
|
||||
};
|
||||
|
||||
/* Structure to hold information for each natural loop. */
|
||||
struct loop
|
||||
{
|
||||
|
@ -142,10 +157,8 @@ struct loop
|
|||
/* Upper bound on number of iterations of a loop. */
|
||||
struct nb_iter_bound *bounds;
|
||||
|
||||
/* If not NULL, loop has just single exit edge stored here (edges to the
|
||||
EXIT_BLOCK_PTR do not count. Do not use directly; this field should
|
||||
only be accessed via single_exit/set_single_exit functions. */
|
||||
edge single_exit_;
|
||||
/* Head of the cyclic list of the exits of the loop. */
|
||||
struct loop_exit exits;
|
||||
};
|
||||
|
||||
/* Flags for state of loop structure. */
|
||||
|
@ -154,7 +167,7 @@ enum
|
|||
LOOPS_HAVE_PREHEADERS = 1,
|
||||
LOOPS_HAVE_SIMPLE_LATCHES = 2,
|
||||
LOOPS_HAVE_MARKED_IRREDUCIBLE_REGIONS = 4,
|
||||
LOOPS_HAVE_MARKED_SINGLE_EXITS = 8
|
||||
LOOPS_HAVE_RECORDED_EXITS = 8
|
||||
};
|
||||
|
||||
#define LOOPS_NORMAL (LOOPS_HAVE_PREHEADERS | LOOPS_HAVE_SIMPLE_LATCHES \
|
||||
|
@ -173,6 +186,11 @@ struct loops
|
|||
/* Array of the loops. */
|
||||
VEC (loop_p, heap) *larray;
|
||||
|
||||
/* Maps edges to the list of their descriptions as loop exits. Edges
|
||||
whose sources or destinations have loop_father == NULL (which may
|
||||
happen during the cfg manipulations) should not appear in EXITS. */
|
||||
htab_t exits;
|
||||
|
||||
/* Pointer to root of loop hierarchy tree. */
|
||||
struct loop *tree_root;
|
||||
};
|
||||
|
@ -184,11 +202,14 @@ extern void flow_loops_dump (FILE *,
|
|||
void (*)(const struct loop *, FILE *, int), int);
|
||||
extern void flow_loop_dump (const struct loop *, FILE *,
|
||||
void (*)(const struct loop *, FILE *, int), int);
|
||||
struct loop *alloc_loop (void);
|
||||
extern void flow_loop_free (struct loop *);
|
||||
int flow_loop_nodes_find (basic_block, struct loop *);
|
||||
void fix_loop_structure (bitmap changed_bbs);
|
||||
void mark_irreducible_loops (void);
|
||||
void mark_single_exit_loops (void);
|
||||
void release_recorded_exits (void);
|
||||
void record_loop_exits (void);
|
||||
void rescan_loop_exit (edge, bool, bool);
|
||||
|
||||
/* Loop data structure manipulation/querying. */
|
||||
extern void flow_loop_tree_node_add (struct loop *, struct loop *);
|
||||
|
@ -210,7 +231,6 @@ extern basic_block *get_loop_body_in_dom_order (const struct loop *);
|
|||
extern basic_block *get_loop_body_in_bfs_order (const struct loop *);
|
||||
extern VEC (edge, heap) *get_loop_exit_edges (const struct loop *);
|
||||
edge single_exit (const struct loop *);
|
||||
void set_single_exit (struct loop *, edge);
|
||||
extern unsigned num_loop_branches (const struct loop *);
|
||||
|
||||
extern edge loop_preheader_edge (const struct loop *);
|
||||
|
|
|
@ -425,7 +425,7 @@ loopify (edge latch_edge, edge header_edge,
|
|||
basic_block *dom_bbs, *body;
|
||||
unsigned n_dom_bbs, i;
|
||||
sbitmap seen;
|
||||
struct loop *loop = XCNEW (struct loop);
|
||||
struct loop *loop = alloc_loop ();
|
||||
struct loop *outer = succ_bb->loop_father->outer;
|
||||
int freq;
|
||||
gcov_type cnt;
|
||||
|
@ -643,7 +643,7 @@ struct loop *
|
|||
duplicate_loop (struct loop *loop, struct loop *target)
|
||||
{
|
||||
struct loop *cloop;
|
||||
cloop = XCNEW (struct loop);
|
||||
cloop = alloc_loop ();
|
||||
place_new_loop (cloop);
|
||||
|
||||
/* Mark the new loop as copy of LOOP. */
|
||||
|
@ -746,65 +746,6 @@ can_duplicate_loop_p (struct loop *loop)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* The NBBS blocks in BBS will get duplicated and the copies will be placed
|
||||
to LOOP. Update the single_exit information in superloops of LOOP. */
|
||||
|
||||
static void
|
||||
update_single_exits_after_duplication (basic_block *bbs, unsigned nbbs,
|
||||
struct loop *loop)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < nbbs; i++)
|
||||
bbs[i]->flags |= BB_DUPLICATED;
|
||||
|
||||
for (; loop->outer; loop = loop->outer)
|
||||
{
|
||||
if (!single_exit (loop))
|
||||
continue;
|
||||
|
||||
if (single_exit (loop)->src->flags & BB_DUPLICATED)
|
||||
set_single_exit (loop, NULL);
|
||||
}
|
||||
|
||||
for (i = 0; i < nbbs; i++)
|
||||
bbs[i]->flags &= ~BB_DUPLICATED;
|
||||
}
|
||||
|
||||
/* Updates single exit information for the copy of LOOP. */
|
||||
|
||||
static void
|
||||
update_single_exit_for_duplicated_loop (struct loop *loop)
|
||||
{
|
||||
struct loop *copy = loop->copy;
|
||||
basic_block src, dest;
|
||||
edge exit = single_exit (loop);
|
||||
|
||||
if (!exit)
|
||||
return;
|
||||
|
||||
src = get_bb_copy (exit->src);
|
||||
dest = exit->dest;
|
||||
if (dest->flags & BB_DUPLICATED)
|
||||
dest = get_bb_copy (dest);
|
||||
|
||||
exit = find_edge (src, dest);
|
||||
gcc_assert (exit != NULL);
|
||||
set_single_exit (copy, exit);
|
||||
}
|
||||
|
||||
/* Updates single exit information for copies of ORIG_LOOPS and their subloops.
|
||||
N is the number of the loops in the ORIG_LOOPS array. */
|
||||
|
||||
static void
|
||||
update_single_exit_for_duplicated_loops (struct loop *orig_loops[], unsigned n)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
update_single_exit_for_duplicated_loop (orig_loops[i]);
|
||||
}
|
||||
|
||||
/* Sets probability and count of edge E to zero. The probability and count
|
||||
is redistributed evenly to the remaining edges coming from E->src. */
|
||||
|
||||
|
@ -1018,10 +959,6 @@ duplicate_loop_to_header_edge (struct loop *loop, edge e,
|
|||
first_active_latch = latch;
|
||||
}
|
||||
|
||||
/* Update the information about single exits. */
|
||||
if (current_loops->state & LOOPS_HAVE_MARKED_SINGLE_EXITS)
|
||||
update_single_exits_after_duplication (bbs, n, target);
|
||||
|
||||
spec_edges[SE_ORIG] = orig;
|
||||
spec_edges[SE_LATCH] = latch_edge;
|
||||
|
||||
|
@ -1036,15 +973,6 @@ duplicate_loop_to_header_edge (struct loop *loop, edge e,
|
|||
place_after);
|
||||
place_after = new_spec_edges[SE_LATCH]->src;
|
||||
|
||||
if (current_loops->state & LOOPS_HAVE_MARKED_SINGLE_EXITS)
|
||||
{
|
||||
for (i = 0; i < n; i++)
|
||||
bbs[i]->flags |= BB_DUPLICATED;
|
||||
update_single_exit_for_duplicated_loops (orig_loops, n_orig_loops);
|
||||
for (i = 0; i < n; i++)
|
||||
bbs[i]->flags &= ~BB_DUPLICATED;
|
||||
}
|
||||
|
||||
if (flags & DLTHE_RECORD_COPY_NUMBER)
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
|
@ -1378,7 +1306,7 @@ loop_version (struct loop *loop,
|
|||
bool place_after)
|
||||
{
|
||||
basic_block first_head, second_head;
|
||||
edge entry, latch_edge, exit, true_edge, false_edge;
|
||||
edge entry, latch_edge, true_edge, false_edge;
|
||||
int irred_flag;
|
||||
struct loop *nloop;
|
||||
basic_block cond_bb;
|
||||
|
@ -1425,10 +1353,6 @@ loop_version (struct loop *loop,
|
|||
false /* Do not redirect all edges. */,
|
||||
then_scale, else_scale);
|
||||
|
||||
exit = single_exit (loop);
|
||||
if (exit)
|
||||
set_single_exit (nloop, find_edge (get_bb_copy (exit->src), exit->dest));
|
||||
|
||||
/* loopify redirected latch_edge. Update its PENDING_STMTS. */
|
||||
lv_flush_pending_stmts (latch_edge);
|
||||
|
||||
|
@ -1539,8 +1463,12 @@ fix_loop_structure (bitmap changed_bbs)
|
|||
bb->aux = NULL;
|
||||
}
|
||||
|
||||
if (current_loops->state & LOOPS_HAVE_MARKED_SINGLE_EXITS)
|
||||
mark_single_exit_loops ();
|
||||
if (current_loops->state & LOOPS_HAVE_MARKED_IRREDUCIBLE_REGIONS)
|
||||
mark_irreducible_loops ();
|
||||
|
||||
if (current_loops->state & LOOPS_HAVE_RECORDED_EXITS)
|
||||
{
|
||||
release_recorded_exits ();
|
||||
record_loop_exits ();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -108,14 +108,16 @@ edges in the strongly connected components that are not natural loops
|
|||
flag is not set for blocks and edges that belong to natural loops that
|
||||
are in such an irreducible region (but it is set for the entry and exit
|
||||
edges of such a loop, if they lead to/from this region).
|
||||
@item @code{LOOPS_HAVE_MARKED_SINGLE_EXITS}: If a loop has exactly one
|
||||
exit edge, this edge is recorded in the loop structure. @code{single_exit}
|
||||
function can be used to retrieve this edge.
|
||||
@item @code{LOOPS_HAVE_RECORDED_EXITS}: The lists of exits are recorded
|
||||
and updated for each loop. This makes some functions (e.g.,
|
||||
@code{get_loop_exit_edges}) more efficient. Some functions (e.g.,
|
||||
@code{single_exit}) can be used only if the lists of exits are
|
||||
recorded.
|
||||
@end itemize
|
||||
|
||||
These properties may also be computed/enforced later, using functions
|
||||
@code{create_preheaders}, @code{force_single_succ_latches},
|
||||
@code{mark_irreducible_loops} and @code{mark_single_exit_loops}.
|
||||
@code{mark_irreducible_loops} and @code{record_loop_exits}.
|
||||
|
||||
The memory occupied by the loops structures should be freed with
|
||||
@code{loop_optimizer_finalize} function.
|
||||
|
|
|
@ -2511,7 +2511,6 @@ perfect_nestify (struct loop *loop,
|
|||
newloop = duplicate_loop (loop, olddest->loop_father);
|
||||
newloop->header = headerbb;
|
||||
newloop->latch = latchbb;
|
||||
set_single_exit (newloop, e);
|
||||
add_bb_to_loop (latchbb, newloop);
|
||||
add_bb_to_loop (bodybb, newloop);
|
||||
add_bb_to_loop (headerbb, newloop);
|
||||
|
|
|
@ -88,8 +88,8 @@ loop_optimizer_init (unsigned flags)
|
|||
if (flags & LOOPS_HAVE_MARKED_IRREDUCIBLE_REGIONS)
|
||||
mark_irreducible_loops ();
|
||||
|
||||
if (flags & LOOPS_HAVE_MARKED_SINGLE_EXITS)
|
||||
mark_single_exit_loops ();
|
||||
if (flags & LOOPS_HAVE_RECORDED_EXITS)
|
||||
record_loop_exits ();
|
||||
|
||||
/* Dump loops. */
|
||||
flow_loops_dump (dump_file, NULL, 1);
|
||||
|
@ -118,6 +118,8 @@ loop_optimizer_finalize (void)
|
|||
}
|
||||
|
||||
/* Clean up. */
|
||||
if (current_loops->state & LOOPS_HAVE_RECORDED_EXITS)
|
||||
release_recorded_exits ();
|
||||
flow_loops_free (current_loops);
|
||||
free (current_loops);
|
||||
current_loops = NULL;
|
||||
|
|
|
@ -892,7 +892,7 @@ sms_schedule (void)
|
|||
gcov_type trip_count = 0;
|
||||
|
||||
loop_optimizer_init (LOOPS_HAVE_PREHEADERS
|
||||
| LOOPS_HAVE_MARKED_SINGLE_EXITS);
|
||||
| LOOPS_HAVE_RECORDED_EXITS);
|
||||
if (!current_loops)
|
||||
return; /* There are no loops to schedule. */
|
||||
|
||||
|
|
|
@ -895,6 +895,7 @@ tree_transform_and_unroll_loop (struct loop *loop, unsigned factor,
|
|||
tree_block_label (rest));
|
||||
bsi_insert_after (&bsi, exit_if, BSI_NEW_STMT);
|
||||
new_exit = make_edge (exit_bb, rest, EDGE_FALSE_VALUE | irr);
|
||||
rescan_loop_exit (new_exit, true, false);
|
||||
new_exit->count = 0;
|
||||
new_exit->probability = 0;
|
||||
new_nonexit = single_pred_edge (loop->latch);
|
||||
|
|
|
@ -44,7 +44,7 @@ static void
|
|||
tree_loop_optimizer_init (void)
|
||||
{
|
||||
loop_optimizer_init (LOOPS_NORMAL
|
||||
| LOOPS_HAVE_MARKED_SINGLE_EXITS);
|
||||
| LOOPS_HAVE_RECORDED_EXITS);
|
||||
if (!current_loops)
|
||||
return;
|
||||
|
||||
|
|
|
@ -862,7 +862,6 @@ slpeel_tree_duplicate_loop_to_edge_cfg (struct loop *loop, edge e)
|
|||
copy_bbs (bbs, loop->num_nodes, new_bbs,
|
||||
&exit, 1, &new_exit, NULL,
|
||||
e->src);
|
||||
set_single_exit (new_loop, new_exit);
|
||||
|
||||
/* Duplicating phi args at exit bbs as coming
|
||||
also from exit of duplicated loop. */
|
||||
|
|
Loading…
Reference in New Issue