summaryrefslogtreecommitdiffstats
path: root/gcc/gcov.c
diff options
context:
space:
mode:
authornathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4>2003-04-06 13:18:41 +0000
committernathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4>2003-04-06 13:18:41 +0000
commitf56e0ced63b906f6e0ef51ec92a1174111692d1f (patch)
treea6fbf3af5cdd76991bee5fa0747e84b86b53a463 /gcc/gcov.c
parent82a50abb8f7a00f7fe19e9277267b5fb07f2c75d (diff)
downloadppe42-gcc-f56e0ced63b906f6e0ef51ec92a1174111692d1f.tar.gz
ppe42-gcc-f56e0ced63b906f6e0ef51ec92a1174111692d1f.zip
.
* gcov.c (struct arc_info): Replace local_span with cycle. (struct block_info): Replace u.span with u.cycle. Add is_call_return. (solve_flow_graph): Set is_call_return. (add_line_counts): Adjust. In block mode, blocks attach to last line. (accumulate_line_counts): Find graph cycles, not spanning tree. (output_branch_count): Adjust. (output_lines): Adjust. * doc/gcov.texi: Update. testsuite: * gcc.misc-test/gcov-9.c: New test. * gcc.misc-test/gcov-10.c: New test * gcc.misc-test/gcov-11.c: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@65299 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/gcov.c')
-rw-r--r--gcc/gcov.c210
1 files changed, 119 insertions, 91 deletions
diff --git a/gcc/gcov.c b/gcc/gcov.c
index e986ac13bd7..95968b585a6 100644
--- a/gcc/gcov.c
+++ b/gcc/gcov.c
@@ -96,9 +96,9 @@ typedef struct arc_info
/* Is an unconditional branch. */
unsigned int is_unconditional : 1;
- /* Arc on the local block spanning tree. */
- unsigned int local_span : 1;
-
+ /* Loop making arc. */
+ unsigned int cycle : 1;
+
/* Next branch on line. */
struct arc_info *line_next;
@@ -128,7 +128,8 @@ typedef struct block_info
unsigned invalid_chain : 1;
/* Block is a call instrumenting site. */
- unsigned is_call_site : 1;
+ unsigned is_call_site : 1; /* Does the call. */
+ unsigned is_call_return : 1; /* Is the return. */
/* Block is a landing pad for longjmp or throw. */
unsigned is_nonlocal_return : 1;
@@ -146,10 +147,11 @@ typedef struct block_info
} line; /* Valid until blocks are linked onto lines */
struct
{
- /* Single line spanning tree workspace. Used for all-blocks mode. */
- struct block_info *root;
- unsigned siblings;
- } span; /* Used in all-blocks mode, after blocks are linked onto
+ /* Single line graph cycle workspace. Used for all-blocks
+ mode. */
+ arc_t *arc;
+ unsigned ident;
+ } cycle; /* Used in all-blocks mode, after blocks are linked onto
lines. */
} u;
@@ -1185,17 +1187,15 @@ solve_flow_graph (fn)
arc->is_unconditional = 1;
/* If this block is instrumenting a call, it might be
an artifical block. It is not artificial if it has
- a non-fallthrough exit, or the destination of the
- exit has more than one entry. */
- if (!arc->fall_through
- || arc->dst->pred != arc || arc->pred_next)
- blk->is_call_site = 0;
+ a non-fallthrough exit, or the destination of this
+ arc has more than one entry. Mark the destination
+ block as a return site, if none of those conditions
+ hold. */
+ if (blk->is_call_site && arc->fall_through
+ && arc->dst->pred == arc && !arc->pred_next)
+ arc->dst->is_call_return = 1;
}
}
- else
- /* If there is more than one exit, it cannot be an artificial
- call instrumenting site. */
- blk->is_call_site = 0;
/* Sort the successor arcs into ascending dst order. profile.c
normally produces arcs in the right order, but sometimes with
@@ -1558,7 +1558,6 @@ add_line_counts (coverage, fn)
unsigned *encoding;
const source_t *src = NULL;
unsigned jx;
- line_t *first_line = NULL;
if (block->count && ix && ix + 1 != fn->num_blocks)
fn->blocks_executed++;
@@ -1585,23 +1584,19 @@ add_line_counts (coverage, fn)
}
line->exists = 1;
line->count += block->count;
- if (!first_line)
- first_line = line;
}
free (block->u.line.encoding);
- block->u.span.root = NULL;
- if (!first_line)
- first_line = line;
-
+ block->u.cycle.arc = NULL;
+ block->u.cycle.ident = ~0U;
+
if (!ix || ix + 1 == fn->num_blocks)
/* Entry or exit block */;
else if (flag_all_blocks)
{
- if (!first_line)
- first_line = &fn->src->lines[fn->line];
+ line_t *block_line = line ? line : &fn->src->lines[fn->line];
- block->chain = first_line->u.blocks;
- first_line->u.blocks = block;
+ block->chain = block_line->u.blocks;
+ block_line->u.blocks = block;
}
else if (flag_branches)
{
@@ -1661,10 +1656,10 @@ accumulate_line_counts (src)
/* The user expects the line count to be the number of times
a line has been executed. Simply summing the block count
will give an artificially high number. The Right Thing
- is to generate the spanning tree of the blocks on this
- line, and the sum the entry arcs to that tree. */
+ is to sum the entry counts to the graph of blocks on this
+ line, then find the elementary cycles of the local graph
+ and add the transition counts of those cycles. */
block_t *block, *block_p, *block_n;
- int changes = 1;
gcov_type count = 0;
/* Reverse the block information */
@@ -1673,77 +1668,110 @@ accumulate_line_counts (src)
{
block_n = block->chain;
block->chain = block_p;
- /* Each block is it's own spanning tree, with no siblings */
- block->u.span.root = block;
- block->u.span.siblings = 0;
+ block->u.cycle.ident = ix;
}
line->u.blocks = block_p;
+
+ /* Sum the entry arcs. */
+ for (block = line->u.blocks; block; block = block->chain)
+ {
+ arc_t *arc;
- while (changes)
+ for (arc = block->pred; arc; arc = arc->pred_next)
+ {
+ if (arc->src->u.cycle.ident != ix)
+ count += arc->count;
+ if (flag_branches)
+ add_branch_counts (&src->coverage, arc);
+ }
+ }
+
+ /* Find the loops. This uses the algorithm described in
+ Tiernan 'An Efficient Search Algorithm to Find the
+ Elementary Circuits of a Graph', CACM Dec 1970. We hold
+ the P array by having each block point to the arc that
+ connects to the previous block. The H array is implicitly
+ held because of the arc ordering, and the block's
+ previous arc pointer.
+
+ Although the algorithm is O(N^3) for highly connected
+ graphs, at worst we'll have O(N^2), as most blocks have
+ only one or two exits. Most graphs will be small.
+
+ For each loop we find, locate the arc with the smallest
+ transition count, and add that to the cumulative
+ count. Remove the arc from consideration. */
+ for (block = line->u.blocks; block; block = block->chain)
{
- changes = 0;
+ block_t *head = block;
+ arc_t *arc;
- for (block = line->u.blocks; block; block = block->chain)
+ next_vertex:;
+ arc = head->succ;
+ current_vertex:;
+ while (arc)
{
- arc_t *arc;
+ block_t *dst = arc->dst;
+ if (/* Already used that arc. */
+ arc->cycle
+ /* Not to same graph, or before first vertex. */
+ || dst->u.cycle.ident != ix
+ /* Already in path. */
+ || dst->u.cycle.arc)
+ {
+ arc = arc->succ_next;
+ continue;
+ }
- for (arc = block->succ; arc; arc = arc->succ_next)
+ if (dst == block)
{
- block_t *dst = arc->dst;
+ /* Found a closing arc. */
+ gcov_type cycle_count = arc->count;
+ arc_t *cycle_arc = arc;
+ arc_t *probe_arc;
- if (!dst->u.span.root)
- /* Not on this line. */;
- else if (dst->u.span.root == block->u.span.root)
- /* Same spanning tree. */;
- else
+ /* Locate the smallest arc count of the loop. */
+ for (dst = head; (probe_arc = dst->u.cycle.arc);
+ dst = probe_arc->src)
+ if (cycle_count > probe_arc->count)
+ {
+ cycle_count = probe_arc->count;
+ cycle_arc = probe_arc;
+ }
+
+ count += cycle_count;
+ cycle_arc->cycle = 1;
+ /* Unwind to the cyclic arc. */
+ while (head != cycle_arc->src)
{
- block_t *root = block->u.span.root;
- block_t *dst_root = dst->u.span.root;
-
- /* Join spanning trees */
- if (root->u.span.siblings
- && !dst_root->u.span.siblings)
- {
- root = dst->u.span.root;
- dst_root = block->u.span.root;
- }
-
- dst_root->u.span.root = root;
- root->u.span.siblings
- += 1 + dst_root->u.span.siblings;
-
- if (dst_root->u.span.siblings)
- {
- block_t *dst_sib;
-
- dst_root->u.span.siblings = 0;
- for (dst_sib = line->u.blocks; dst_sib;
- dst_sib = dst_sib->chain)
- if (dst_sib->u.span.root == dst_root)
- dst_sib->u.span.root = root;
- }
- arc->local_span = 1;
- changes = 1;
+ arc = head->u.cycle.arc;
+ head = arc->src;
}
+ /* Move on. */
+ arc = arc->succ_next;
+ continue;
}
+
+ /* Add new block to chain. */
+ dst->u.cycle.arc = arc;
+ head = dst;
+ goto next_vertex;
}
- }
-
- /* Now sum the entry counts */
- for (block = line->u.blocks; block; block = block->chain)
- {
- arc_t *arc;
-
- for (arc = block->succ; arc; arc = arc->succ_next)
+ /* We could not add another vertex to the path. Remove
+ the last vertex from the list. */
+ arc = head->u.cycle.arc;
+ if (arc)
{
- if (!arc->local_span)
- count += arc->count;
- if (flag_branches)
- add_branch_counts (&src->coverage, arc);
+ /* It was not the first vertex. Move onto next arc. */
+ head->u.cycle.arc = NULL;
+ head = arc->src;
+ arc = arc->succ_next;
+ goto current_vertex;
}
- block->u.span.root = NULL;
+ /* Mark this block as unusable. */
+ block->u.cycle.ident = ~0U;
}
-
+
line->count = count;
}
@@ -1786,7 +1814,7 @@ output_branch_count (gcov_file, ix, arc)
else
fnotice (gcov_file, "branch %2d never executed\n", ix);
}
- else if (flag_unconditional && !arc->src->is_call_site)
+ else if (flag_unconditional && !arc->dst->is_call_return)
{
if (arc->src->count)
fnotice (gcov_file, "unconditional %2d taken %s\n", ix,
@@ -1895,17 +1923,17 @@ output_lines (gcov_file, src)
if (flag_all_blocks)
{
block_t *block;
+ arc_t *arc;
int ix, jx;
for (ix = jx = 0, block = line->u.blocks; block;
block = block->chain)
{
- arc_t *arc;
-
- if (!block->is_call_site)
+ if (!block->is_call_return)
fprintf (gcov_file, "%9s:%5u-block %2d\n",
!line->exists ? "-" : !block->count ? "$$$$$"
- : format_gcov (block->count, 0, -1), line_num, ix++);
+ : format_gcov (block->count, 0, -1),
+ line_num, ix++);
if (flag_branches)
for (arc = block->succ; arc; arc = arc->succ_next)
jx += output_branch_count (gcov_file, jx, arc);
OpenPOWER on IntegriCloud