diff options
author | Nathan Sidwell <nathan@acm.org> | 2011-12-02 20:32:40 +0000 |
---|---|---|
committer | Nathan Sidwell <nathan@gcc.gnu.org> | 2011-12-02 20:32:40 +0000 |
commit | 8919c0d984f1d98b612268e938668f177d5f835f (patch) | |
tree | 8ef74f6b3ac710dbaffba4b31b1cf46d2bbf5382 /gcc/gcov.c | |
parent | 134dc576a298b36dbbe5048b0acdf11e53838464 (diff) | |
download | gcc-8919c0d984f1d98b612268e938668f177d5f835f.zip gcc-8919c0d984f1d98b612268e938668f177d5f835f.tar.gz gcc-8919c0d984f1d98b612268e938668f177d5f835f.tar.bz2 |
gcov.c (struct arc_info): Add is_throw field.
* gcov.c (struct arc_info): Add is_throw field.
(struct (block_info): Add exceptional field, reduce flags size to
account for it.
(struct function_info): Add has_catch field.
(struct line_info): Add unexceptional field.
(process_file): Call find_exception_blocks if necessary.
(read_graph_file): Adjust. Note if an exceptional edge is seen.
(find_exception_blocks): New.
(add_line_counts): Set line's unexceptional flag if not
exceptional.
(output_branch_count): Note exceptional arcs, lines and blocks.
* gcov-dump.c (tag_arcs): Decode arc flags.
* doc/gcov.texi: Document '=====' lines.
testsuite/
* lib/gcov.exp (verify-lines): Allow = as a count char.
* g++.dg/gcov/gcov-13.C: New.
From-SVN: r181949
Diffstat (limited to 'gcc/gcov.c')
-rw-r--r-- | gcc/gcov.c | 87 |
1 files changed, 73 insertions, 14 deletions
@@ -88,6 +88,9 @@ typedef struct arc_info unsigned int fake : 1; unsigned int fall_through : 1; + /* Arc to a catch handler. */ + unsigned int is_throw : 1; + /* Arc is for a function that abnormally returns. */ unsigned int is_call_non_return : 1; @@ -123,10 +126,11 @@ typedef struct block_info /* Block execution count. */ gcov_type count; - unsigned flags : 13; + unsigned flags : 12; unsigned count_valid : 1; unsigned valid_chain : 1; unsigned invalid_chain : 1; + unsigned exceptional : 1; /* Block is a call instrumenting site. */ unsigned is_call_site : 1; /* Does the call. */ @@ -172,6 +176,9 @@ typedef struct function_info unsigned lineno_checksum; unsigned cfg_checksum; + /* The graph contains at least one fake incoming edge. */ + unsigned has_catch : 1; + /* Array of basic blocks. */ block_t *blocks; unsigned num_blocks; @@ -224,6 +231,7 @@ typedef struct line_info in all-blocks mode. */ } u; unsigned exists : 1; + unsigned unexceptional : 1; } line_t; /* Describes a file mentioned in the block graph. Contains an array @@ -369,6 +377,7 @@ static unsigned find_source (const char *); static function_t *read_graph_file (void); static int read_count_file (function_t *); static void solve_flow_graph (function_t *); +static void find_exception_blocks (function_t *); static void add_branch_counts (coverage_t *, const arc_t *); static void add_line_counts (coverage_t *, function_t *); static void function_summary (const coverage_t *, const char *); @@ -628,6 +637,8 @@ process_file (const char *file_name) sources[src].num_lines = line + 1; solve_flow_graph (fn); + if (fn->has_catch) + find_exception_blocks (fn); *fn_end = fn; fn_end = &fn->next; } @@ -1051,13 +1062,15 @@ read_graph_file (void) { unsigned src = gcov_read_unsigned (); unsigned num_dests = GCOV_TAG_ARCS_NUM (length); + block_t *src_blk = &fn->blocks[src]; + unsigned mark_catches = 0; + struct arc_info *arc; if (src >= fn->num_blocks || fn->blocks[src].succ) goto corrupt; while (num_dests--) { - struct arc_info *arc; unsigned dest = gcov_read_unsigned (); unsigned flags = gcov_read_unsigned (); @@ -1066,7 +1079,7 @@ read_graph_file (void) arc = XCNEW (arc_t); arc->dst = &fn->blocks[dest]; - arc->src = &fn->blocks[src]; + arc->src = src_blk; arc->count = 0; arc->count_valid = 0; @@ -1074,9 +1087,9 @@ read_graph_file (void) arc->fake = !!(flags & GCOV_ARC_FAKE); arc->fall_through = !!(flags & GCOV_ARC_FALLTHROUGH); - arc->succ_next = fn->blocks[src].succ; - fn->blocks[src].succ = arc; - fn->blocks[src].num_succ++; + arc->succ_next = src_blk->succ; + src_blk->succ = arc; + src_blk->num_succ++; arc->pred_next = fn->blocks[dest].pred; fn->blocks[dest].pred = arc; @@ -1090,12 +1103,12 @@ read_graph_file (void) source block must be a call. */ fn->blocks[src].is_call_site = 1; arc->is_call_non_return = 1; + mark_catches = 1; } else { /* Non-local return from a callee of this - function. The destination block is a catch or - setjmp. */ + function. The destination block is a setjmp. */ arc->is_nonlocal_return = 1; fn->blocks[dest].is_nonlocal_return = 1; } @@ -1104,6 +1117,20 @@ read_graph_file (void) if (!arc->on_tree) fn->num_counts++; } + + if (mark_catches) + { + /* We have a fake exit from this block. The other + non-fall through exits must be to catch handlers. + Mark them as catch arcs. */ + + for (arc = src_blk->succ; arc; arc = arc->succ_next) + if (!arc->fake && !arc->fall_through) + { + arc->is_throw = 1; + fn->has_catch = 1; + } + } } else if (fn && tag == GCOV_TAG_LINES) { @@ -1543,6 +1570,34 @@ solve_flow_graph (function_t *fn) } } +/* Mark all the blocks only reachable via an incoming catch. */ + +static void +find_exception_blocks (function_t *fn) +{ + unsigned ix; + block_t **queue = XALLOCAVEC (block_t *, fn->num_blocks); + + /* First mark all blocks as exceptional. */ + for (ix = fn->num_blocks; ix--;) + fn->blocks[ix].exceptional = 1; + + /* Now mark all the blocks reachable via non-fake edges */ + queue[0] = fn->blocks; + queue[0]->exceptional = 0; + for (ix = 1; ix;) + { + block_t *block = queue[--ix]; + const arc_t *arc; + + for (arc = block->succ; arc; arc = arc->succ_next) + if (!arc->fake && !arc->is_throw && arc->dst->exceptional) + { + arc->dst->exceptional = 0; + queue[ix++] = arc->dst; + } + } +} /* Increment totals in COVERAGE according to arc ARC. */ @@ -1860,6 +1915,8 @@ add_line_counts (coverage_t *coverage, function_t *fn) coverage->lines_executed++; } line->exists = 1; + if (!block->exceptional) + line->unexceptional = 1; line->count += block->count; } free (block->u.line.encoding); @@ -2082,7 +2139,6 @@ accumulate_line_counts (source_t *src) static int output_branch_count (FILE *gcov_file, int ix, const arc_t *arc) { - if (arc->is_call_non_return) { if (arc->src->count) @@ -2099,7 +2155,8 @@ output_branch_count (FILE *gcov_file, int ix, const arc_t *arc) if (arc->src->count) fnotice (gcov_file, "branch %2d taken %s%s\n", ix, format_gcov (arc->count, arc->src->count, -flag_counts), - arc->fall_through ? " (fallthrough)" : ""); + arc->fall_through ? " (fallthrough)" + : arc->is_throw ? " (throw)" : ""); else fnotice (gcov_file, "branch %2d never executed\n", ix); } @@ -2182,8 +2239,9 @@ output_lines (FILE *gcov_file, const source_t *src) 16 spaces of indentation added before the source line so that tabs won't be messed up. */ fprintf (gcov_file, "%9s:%5u:", - !line->exists ? "-" : !line->count ? "#####" - : format_gcov (line->count, 0, -1), line_num); + !line->exists ? "-" : line->count + ? format_gcov (line->count, 0, -1) + : line->unexceptional ? "#####" : "=====", line_num); if (retval) { @@ -2211,8 +2269,9 @@ output_lines (FILE *gcov_file, const source_t *src) { if (!block->is_call_return) fprintf (gcov_file, "%9s:%5u-block %2d\n", - !line->exists ? "-" : !block->count ? "$$$$$" - : format_gcov (block->count, 0, -1), + !line->exists ? "-" : block->count + ? format_gcov (block->count, 0, -1) + : block->exceptional ? "%%%%%" : "$$$$$", line_num, ix++); if (flag_branches) for (arc = block->succ; arc; arc = arc->succ_next) |