aboutsummaryrefslogtreecommitdiff
path: root/gcc/cfgloop.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cfgloop.c')
-rw-r--r--gcc/cfgloop.c122
1 files changed, 120 insertions, 2 deletions
diff --git a/gcc/cfgloop.c b/gcc/cfgloop.c
index 58d9dd0..b5553d2 100644
--- a/gcc/cfgloop.c
+++ b/gcc/cfgloop.c
@@ -370,6 +370,63 @@ flow_loop_nodes_find (basic_block header, struct loop *loop)
return num_nodes;
}
+/* For each loop in the lOOPS tree that has just a single exit
+ record the exit edge. */
+
+void
+mark_single_exit_loops (struct loops *loops)
+{
+ basic_block bb;
+ edge e;
+ struct loop *loop;
+ unsigned i;
+
+ for (i = 1; i < loops->num; i++)
+ {
+ loop = loops->parray[i];
+ if (loop)
+ loop->single_exit = NULL;
+ }
+
+ FOR_EACH_BB (bb)
+ {
+ if (bb->loop_father == loops->tree_root)
+ continue;
+ for (e = bb->succ; e; e = e->succ_next)
+ {
+ 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 (loop->single_exit)
+ loop->single_exit = ENTRY_BLOCK_PTR->succ;
+ else
+ loop->single_exit = e;
+ }
+ }
+ }
+
+ for (i = 1; i < loops->num; i++)
+ {
+ loop = loops->parray[i];
+ if (!loop)
+ continue;
+
+ if (loop->single_exit == ENTRY_BLOCK_PTR->succ)
+ loop->single_exit = NULL;
+ }
+
+ loops->state |= LOOPS_HAVE_MARKED_SINGLE_EXITS;
+}
+
/* Find the root node of the loop pre-header extended basic block and
the edges along the trace from the root node to the loop header. */
@@ -1197,8 +1254,6 @@ verify_loop_structure (struct loops *loops)
}
}
- free (sizes);
-
/* Check get_loop_body. */
for (i = 1; i < loops->num; i++)
{
@@ -1319,8 +1374,71 @@ verify_loop_structure (struct loops *loops)
free (irreds);
}
+ /* Check the single_exit. */
+ if (loops->state & LOOPS_HAVE_MARKED_SINGLE_EXITS)
+ {
+ memset (sizes, 0, sizeof (unsigned) * loops->num);
+ FOR_EACH_BB (bb)
+ {
+ if (bb->loop_father == loops->tree_root)
+ continue;
+ for (e = bb->succ; e; e = e->succ_next)
+ {
+ 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)
+ {
+ sizes[loop->num]++;
+ if (loop->single_exit
+ && loop->single_exit != e)
+ {
+ error ("Wrong single exit %d->%d recorded for loop %d.",
+ loop->single_exit->src->index,
+ loop->single_exit->dest->index,
+ loop->num);
+ error ("Right exit is %d->%d.",
+ e->src->index, e->dest->index);
+ err = 1;
+ }
+ }
+ }
+ }
+
+ for (i = 1; i < loops->num; i++)
+ {
+ loop = loops->parray[i];
+ if (!loop)
+ continue;
+
+ if (sizes[i] == 1
+ && !loop->single_exit)
+ {
+ error ("Single exit not recorded for loop %d.", loop->num);
+ err = 1;
+ }
+
+ if (sizes[i] != 1
+ && loop->single_exit)
+ {
+ error ("Loop %d should not have single exit (%d -> %d).",
+ loop->num,
+ loop->single_exit->src->index,
+ loop->single_exit->dest->index);
+ err = 1;
+ }
+ }
+ }
+
if (err)
abort ();
+
+ free (sizes);
}
/* Returns latch edge of LOOP. */