@@ -437,15 +437,24 @@ extern int main (int, char **);
simple paths)--the node is unblocked only when it participates in a cycle.
*/
-/* Flag that drives cycle detection after a negative cycle is seen. */
-static bool did_negate = false;
+typedef vector<arc_t *> arc_vector_t;
+typedef vector<const block_t *> block_vector_t;
+
+/* Enum with types of loop in CFG. */
+
+enum loop_type
+{
+ NO_LOOP,
+ LOOP,
+ NEGATIVE_LOOP
+};
/* Handle cycle identified by EDGES, where the function finds minimum cs_count
and subtract the value from all counts. The subtracted value is added
- to COUNT. */
+ to COUNT. Returns type of loop. */
-static void
-handle_cycle (const vector<arc_t *> &edges, int64_t &count)
+static loop_type
+handle_cycle (const arc_vector_t &edges, int64_t &count)
{
/* Find the minimum edge of the cycle, and reduce all nodes in the cycle by
that amount. */
@@ -460,25 +469,24 @@ handle_cycle (const vector<arc_t *> &edges, int64_t &count)
for (unsigned i = 0; i < edges.size (); i++)
edges[i]->cs_count -= cycle_count;
- if (cycle_count < 0)
- did_negate = true;
+ return cycle_count < 0 ? NEGATIVE_LOOP : LOOP;
}
/* Unblock a block U from BLOCKED. Apart from that, iterate all blocks
blocked by U in BLOCK_LISTS. */
static void
-unblock (block_t *u, vector<block_t *> &blocked,
- vector<vector<block_t *> > &block_lists)
+unblock (const block_t *u, block_vector_t &blocked,
+ vector<block_vector_t > &block_lists)
{
- vector<block_t *>::iterator it = find (blocked.begin (), blocked.end (), u);
+ block_vector_t::iterator it = find (blocked.begin (), blocked.end (), u);
if (it == blocked.end ())
return;
unsigned index = it - blocked.begin ();
blocked.erase (it);
- for (vector<block_t *>::iterator it2 = block_lists[index].begin ();
+ for (block_vector_t::iterator it2 = block_lists[index].begin ();
it2 != block_lists[index].end (); it2++)
unblock (*it2, blocked, block_lists);
for (unsigned j = 0; j < block_lists[index].size (); j++)
@@ -489,19 +497,20 @@ unblock (block_t *u, vector<block_t *> &blocked,
/* Find circuit going to block V, PATH is provisional seen cycle.
BLOCKED is vector of blocked vertices, BLOCK_LISTS contains vertices
- blocked by a block. COUNT is accumulated count of the current LINE. */
+ blocked by a block. COUNT is accumulated count of the current LINE.
+ Returns what type of loop it contains. */
-static bool
-circuit (block_t *v, vector<arc_t *> &path, block_t *start,
- vector<block_t *> &blocked, vector<vector<block_t *>> &block_lists,
+static loop_type
+circuit (block_t *v, arc_vector_t &path, block_t *start,
+ block_vector_t &blocked, vector<block_vector_t> &block_lists,
line_t &linfo, int64_t &count)
{
- bool found = false;
+ loop_type result = NO_LOOP;
/* Add v to the block list. */
gcc_assert (find (blocked.begin (), blocked.end (), v) == blocked.end ());
blocked.push_back (v);
- block_lists.push_back (vector<block_t *> ());
+ block_lists.push_back (block_vector_t ());
for (arc_t *arc = v->succ; arc; arc = arc->succ_next)
{
@@ -513,16 +522,22 @@ circuit (block_t *v, vector<arc_t *> &path, block_t *start,
if (w == start)
{
/* Cycle has been found. */
- handle_cycle (path, count);
- found = true;
+ loop_type cresult = handle_cycle (path, count);
+ if (cresult > result)
+ result = cresult;
}
else if (find (blocked.begin (), blocked.end (), w) == blocked.end ())
- found |= circuit (w, path, start, blocked, block_lists, linfo, count);
+ {
+ loop_type cresult = circuit (w, path, start, blocked, block_lists,
+ linfo, count);
+ if (cresult > result)
+ result = cresult;
+ }
path.pop_back ();
}
- if (found)
+ if (result != NO_LOOP)
unblock (v, blocked, block_lists);
else
for (arc_t *arc = v->succ; arc; arc = arc->succ_next)
@@ -534,18 +549,19 @@ circuit (block_t *v, vector<arc_t *> &path, block_t *start,
size_t index
= find (blocked.begin (), blocked.end (), w) - blocked.begin ();
gcc_assert (index < blocked.size ());
- vector<block_t *> &list = block_lists[index];
+ block_vector_t &list = block_lists[index];
if (find (list.begin (), list.end (), v) == list.end ())
list.push_back (v);
}
- return found;
+ return result;
}
-/* Find cycles for a LINFO. */
+/* Find cycles for a LINFO. If HANDLE_NEGATIVE_CYCLES is set and the line
+ contains a negative loop, then perform the same function once again. */
static gcov_type
-find_cycles (line_t &linfo)
+get_cycles_count (line_t &linfo, bool handle_negative_cycles = true)
{
/* Note that this algorithm works even if blocks aren't in sorted order.
Each iteration of the circuit detection is completely independent
@@ -553,32 +569,19 @@ find_cycles (line_t &linfo)
Therefore, operating on a permuted order (i.e., non-sorted) only
has the effect of permuting the output cycles. */
+ loop_type result = NO_LOOP;
gcov_type count = 0;
for (block_t *block = linfo.u.blocks; block; block = block->chain)
{
- vector<arc_t *> path;
- vector<block_t *> blocked;
- vector<vector<block_t *> > block_lists;
- circuit (block, path, block, blocked, block_lists, linfo, count);
+ arc_vector_t path;
+ block_vector_t blocked;
+ vector<block_vector_t > block_lists;
+ result = circuit (block, path, block, blocked, block_lists, linfo, count);
}
- return count;
-}
-
-/* Get cycle count for a LINFO. */
-
-static gcov_type
-get_cycles_count (line_t &linfo)
-{
- gcov_type count = 0;
-
- /* Bug compatibility with gcc's broken cycle-finder: if a negative cycle
- exists, run the algorithm again. */
-
- did_negate = false;
- count = find_cycles (linfo);
- if (did_negate)
- count += find_cycles (linfo);
+ /* If we have a negative cycle, repeat the find_cycles routine. */
+ if (result == NEGATIVE_LOOP && handle_negative_cycles)
+ count += get_cycles_count (linfo, false);
return count;
}