gcov.c: Add -a & -u options.

* gcov.c: Add -a & -u options.
	(struct arc_info): Add local_span, is_call_non_return,
	is_nonlocal_return, is_unconditional flags, remove is_call flag.
	(struct block_info): Add flags, is_call_site, is_nonlocal_return
	members. Make encodings a union with span member.
	(struct function_info): Add blocks_executed, line, src, line_next
	members.
	(struct coverage_info): Make branches a union with blocks member.
	(struct source_info): Add functions member.
	(object_summary, program_count): New global variables.
	(flag_all_blocks, flag_unconditional): New flags.
	(find_source, output_branch_count): New functions.
	(print_usage): Adjust.
	(options): Adjust.
	(process_args): Adjust.
	(read_graph_file) <GCOV_TAG_FUNCTION>: Adjust.
	<GCOV_TAG_BLOCKS>: Read flags.
	<GCOV_TAG_LINES>: Adjust.
	(read_count_file): Process SUMMARY tags.
	(solve_flow_graph): Set is_unconditional and clear is_call_site
	appropriately.
	(add_branch_counts): Adjust. Don't count unconditional branches.
	(add_line_counts): Deal with all-blocks mode, accumulate block
	coverage.
	(accumulate_line_counts): Adjust, generate local spanning tree for
	all-blocks mode.
	(output_lines): Adjust.
	* profile.c (branch_prob): Alter GCOV_FUNCTION_TAG record.
	* doc/gcov.texi: Document.
testsuite:
	* lib/gcov.exp: Adjust call return testing strings.
	* g77.dg/gcov/gcov-1.f: Don't expect unconditional branches.

From-SVN: r65090
This commit is contained in:
Nathan Sidwell 2003-03-31 15:18:24 +00:00 committed by Nathan Sidwell
parent 212d93131f
commit 27283c7340
8 changed files with 584 additions and 135 deletions

View File

@ -1,3 +1,35 @@
2003-03-31 Nathan Sidwell <nathan@codesourcery.com>
* gcov.c: Add -a & -u options.
(struct arc_info): Add local_span, is_call_non_return,
is_nonlocal_return, is_unconditional flags, remove is_call flag.
(struct block_info): Add flags, is_call_site, is_nonlocal_return
members. Make encodings a union with span member.
(struct function_info): Add blocks_executed, line, src, line_next
members.
(struct coverage_info): Make branches a union with blocks member.
(struct source_info): Add functions member.
(object_summary, program_count): New global variables.
(flag_all_blocks, flag_unconditional): New flags.
(find_source, output_branch_count): New functions.
(print_usage): Adjust.
(options): Adjust.
(process_args): Adjust.
(read_graph_file) <GCOV_TAG_FUNCTION>: Adjust.
<GCOV_TAG_BLOCKS>: Read flags.
<GCOV_TAG_LINES>: Adjust.
(read_count_file): Process SUMMARY tags.
(solve_flow_graph): Set is_unconditional and clear is_call_site
appropriately.
(add_branch_counts): Adjust. Don't count unconditional branches.
(add_line_counts): Deal with all-blocks mode, accumulate block
coverage.
(accumulate_line_counts): Adjust, generate local spanning tree for
all-blocks mode.
(output_lines): Adjust.
* profile.c (branch_prob): Alter GCOV_FUNCTION_TAG record.
* doc/gcov.texi: Document.
2003-03-31 Kazu Hirata <kazu@cs.umass.edu>
* config/h8300/h8300.md: Organize peephole2's that trasform

View File

@ -120,6 +120,7 @@ gcov @r{[}@var{options}@r{]} @var{sourcefile}
@ignore
@c man begin SYNOPSIS
gcov [@option{-v}|@option{--version}] [@option{-h}|@option{--help}]
[@option{-a}|@option{--all-blocks}]
[@option{-b}|@option{--branch-probabilities}]
[@option{-c}|@option{--branch-counts}]
[@option{-n}|@option{--no-output}]
@ -127,6 +128,7 @@ gcov [@option{-v}|@option{--version}] [@option{-h}|@option{--help}]
[@option{-p}|@option{--preserve-paths}]
[@option{-f}|@option{--function-summaries}]
[@option{-o}|@option{--object-directory} @var{directory|file}] @var{sourcefile}
[@option{-u}|@option{--unconditional-branches}]
@c man end
@c man begin SEEALSO
gpl(7), gfdl(7), fsf-funding(7), gcc(1) and the Info entry for @file{gcc}.
@ -145,11 +147,23 @@ exit without doing any further processing.
Display the @command{gcov} version number (on the standard output),
and exit without doing any further processing.
@item -a
@itemx --all-blocks
Write individual execution counts for every basic block. Normally gcov
outputs execution counts only for the main blocks of a line. With this
option you can determine if blocks within a single line are not being
executed. In this mode each block is shown, and contributes to the
occupancy and execution count of, the first line of source that it
contains. A multi-line block will only contribute to that first line,
and other lines will not be show to contain code, unless a subsequent
block begins on those lines.
@item -b
@itemx --branch-probabilities
Write branch frequencies to the output file, and write branch summary
info to the standard output. This option allows you to see how often
each branch in your program was taken.
each branch in your program was taken. Unconditional branches will not
be shown, unless the @option{-u} option is given.
@item -c
@itemx --branch-counts
@ -192,6 +206,11 @@ source file name, without its extension. If a file is specified here,
the data files are named after that file, without its extension. If this
option is not supplied, it defaults to the current directory.
@item -u
@itemx --unconditional-branches
When branch counts are given, include those of unconditional branches.
Unconditional branches are normally not interesting.
@end table
Gcov should be run with the current directory the same as that when you
@ -248,10 +267,14 @@ Here is a sample:
@smallexample
-: 0:Source:tmp.c
-: 0:Object:tmp.bb
-: 0:Graph:tmp.bbg
-: 0:Data:tmp.da
-: 0:Runs:1
-: 0:Programs:1
-: 1:#include <stdio.h>
-: 2:
-: 3:int main (void)
function main called 1 returned 1 blocks executed 75%
1: 4:@{
1: 5: int i, total;
-: 6:
@ -265,9 +288,47 @@ Here is a sample:
-: 14: else
1: 15: printf ("Success\n");
1: 16: return 0;
1: 17:@}
-: 17:@}
@end smallexample
When you use the @option{-a} option, you will get individual block
counts, and the output looks like this:
@smallexample
-: 0:Source:tmp.c
-: 0:Graph:tmp.bbg
-: 0:Data:tmp.da
-: 0:Runs:1
-: 0:Programs:1
-: 1:#include <stdio.h>
-: 2:
-: 3:int main (void)
function main called 1 returned 1 blocks executed 75%
1: 4:@{
1: 4-block 0
1: 5: int i, total;
-: 6:
1: 7: total = 0;
-: 8:
11: 9: for (i = 0; i < 10; i++)
11: 9-block 0
10: 10: total += i;
10: 10-block 0
-: 11:
1: 12: if (total != 45)
1: 12-block 0
#####: 13: printf ("Failure\n");
$$$$$: 13-block 0
-: 14: else
1: 15: printf ("Success\n");
1: 15-block 0
1: 16: return 0;
1: 16-block 0
-: 17:@}
@end smallexample
As you can see, line 13 contains a basic block that was not executed.
@need 450
When you use the @option{-b} option, your output looks like this:
@ -284,31 +345,34 @@ Here is a sample of a resulting @file{tmp.c.gcov} file:
@smallexample
-: 0:Source:tmp.c
-: 0:Object:tmp.bb
-: 0:Graph:tmp.bbg
-: 0:Data:tmp.da
-: 0:Runs:1
-: 0:Programs:1
-: 1:#include <stdio.h>
-: 2:
-: 3:int main (void)
function main called 1 returned 1 blocks executed 75%
1: 4:@{
1: 5: int i, total;
-: 6:
1: 7: total = 0;
-: 8:
11: 9: for (i = 0; i < 10; i++)
branch 0: taken 90%
branch 1: taken 100%
branch 2: taken 100%
branch 0 taken 91% (fallthrough)
branch 1 taken 9%
10: 10: total += i;
-: 11:
1: 12: if (total != 45)
branch 0: taken 100%
branch 0 taken 0% (fallthrough)
branch 1 taken 100%
#####: 13: printf ("Failure\n");
call 0: never executed
branch 1: never executed
call 0 never executed
-: 14: else
1: 15: printf ("Success\n");
call 0: returns 100%
call 0 called 1 returned 100%
1: 16: return 0;
1: 17:@}
-: 17:@}
@end smallexample
For each basic block, a line is printed after the last line of the basic

View File

@ -90,6 +90,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
bbg: function-graph*
function-graph: announce_function basic_blocks {arcs | lines}*
announce_function: header string:name int32:checksum
string:source int32:lineno
basic_block: header int32:flags*
arcs: header int32:block_no arc*
arc: int32:dest_block int32:flags
@ -121,7 +122,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
summary: in32:checksum int32:runs int32:arcs int64:sum int64:max \
int64:max_sum int64:sum_max
The ANNOUNCE_FUNCTION record is the same as that in the BBG file.
The ANNOUNCE_FUNCTION record is the same as that in the BBG file,
but without the source location.
The ARC_COUNTS gives the counter values for those arcs that are
instrumented. The SUMMARY records give information about the whole
object file and about the whole program. The checksum is used for
@ -195,7 +197,7 @@ typedef long long gcov_type;
(GCOV_TAG_MASK (TAG) > GCOV_TAG_MASK (SUB))
/* Basic block flags. */
#define GCOV_BLOCK_UNEXPECTED (1 << 0)
#define GCOV_BLOCK_UNEXPECTED (1 << 1)
/* Arc flags. */
#define GCOV_ARC_ON_TREE (1 << 0)

View File

@ -69,6 +69,7 @@ typedef HOST_WIDEST_INT gcov_type;
struct function_info;
struct block_info;
struct source_info;
/* Describes an arc between two basic blocks. */
@ -86,8 +87,17 @@ typedef struct arc_info
unsigned int fake : 1;
unsigned int fall_through : 1;
/* Arc to a call. */
unsigned int is_call : 1;
/* Arc is for a function that abnormally returns. */
unsigned int is_call_non_return : 1;
/* Arc is for catch/setjump. */
unsigned int is_nonlocal_return : 1;
/* Is an unconditional branch. */
unsigned int is_unconditional : 1;
/* Arc on the local block spanning tree. */
unsigned int local_span : 1;
/* Next branch on line. */
struct arc_info *line_next;
@ -112,17 +122,39 @@ typedef struct block_info
/* Block execution count. */
gcov_type count;
unsigned flags : 13;
unsigned count_valid : 1;
unsigned valid_chain : 1;
unsigned invalid_chain : 1;
/* Array of line numbers and source files. source files are
introduced by a linenumber of zero, the next 'line number' is the
number of the source file. Always starts with a source file. */
unsigned *encoding;
unsigned num_encodings;
/* Block is a call instrumenting site. */
unsigned is_call_site : 1;
/* Temporary chain for solving graph. */
/* Block is a landing pad for longjmp or throw. */
unsigned is_nonlocal_return : 1;
union
{
struct
{
/* Array of line numbers and source files. source files are
introduced by a linenumber of zero, the next 'line number' is
the number of the source file. Always starts with a source
file. */
unsigned *encoding;
unsigned num;
} 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
lines. */
} u;
/* Temporary chain for solving graph, and for chaining blocks on one
line. */
struct block_info *chain;
} block_t;
@ -138,10 +170,18 @@ typedef struct function_info
/* Array of basic blocks. */
block_t *blocks;
unsigned num_blocks;
unsigned blocks_executed;
/* Raw arc coverage counts. */
gcov_type *counts;
unsigned num_counts;
/* First line number. */
unsigned line;
struct source_info *src;
/* Next function in same source file. */
struct function_info *line_next;
/* Next function. */
struct function_info *next;
@ -170,8 +210,14 @@ typedef struct coverage_info
typedef struct line_info
{
gcov_type count; /* execution count */
arc_t *branches; /* branches from blocks that end on this
line. */
union
{
arc_t *branches; /* branches from blocks that end on this
line. Used for branch-counts when not
all-blocks mode. */
block_t *blocks; /* blocks which start on this line. Used
in all-blocks mode. */
} u;
unsigned exists : 1;
} line_t;
@ -189,6 +235,10 @@ typedef struct source_info
unsigned num_lines;
coverage_t coverage;
/* Functions in this source file. These are in ascending line
number order. */
function_t *functions;
/* Next source file. */
struct source_info *next;
@ -202,6 +252,11 @@ static function_t *functions;
static source_t *sources;
/* This holds data summary information. */
static struct gcov_summary object_summary;
static unsigned program_count;
/* Modification time of graph file. */
static time_t bbg_file_time;
@ -218,6 +273,9 @@ static char *da_file_name;
static int flag_branches = 0;
/* Show unconditional branches too. */
static int flag_unconditional = 0;
/* Output a gcov file if this is true. This is on by default, and can
be turned off by the -n option. */
@ -229,6 +287,11 @@ static int flag_gcov_file = 1;
static int flag_long_names = 0;
/* Output count information for every basic block, not merely those
that contain line number information. */
static int flag_all_blocks = 0;
/* Output summary info for each function. */
static int flag_function_summary = 0;
@ -256,14 +319,16 @@ static void print_usage PARAMS ((int)) ATTRIBUTE_NORETURN;
static void print_version PARAMS ((void)) ATTRIBUTE_NORETURN;
static void process_file PARAMS ((const char *));
static void create_file_names PARAMS ((const char *));
static source_t *find_source PARAMS ((char *));
static int read_graph_file PARAMS ((void));
static int read_count_file PARAMS ((void));
static void solve_flow_graph PARAMS ((function_t *));
static void add_branch_counts PARAMS ((coverage_t *, const arc_t *));
static void add_line_counts PARAMS ((coverage_t *, const function_t *));
static void add_line_counts PARAMS ((coverage_t *, function_t *));
static void function_summary PARAMS ((const coverage_t *, const char *));
static const char *format_gcov PARAMS ((gcov_type, gcov_type, int));
static void accumulate_line_counts PARAMS ((source_t *));
static int output_branch_count PARAMS ((FILE *, int, const arc_t *));
static void output_lines PARAMS ((FILE *, const source_t *));
static char *make_gcov_file_name PARAMS ((const char *, const char *));
static void release_structures PARAMS ((void));
@ -328,6 +393,7 @@ print_usage (error_p)
fnotice (file, "Print code coverage information.\n\n");
fnotice (file, " -h, --help Print this help, then exit\n");
fnotice (file, " -v, --version Print version number, then exit\n");
fnotice (file, " -a, --all-blocks Show information for every basic block\n");
fnotice (file, " -b, --branch-probabilities Include branch probabilities in output\n");
fnotice (file, " -c, --branch-counts Given counts of branches taken\n\
rather than percentages\n");
@ -337,6 +403,7 @@ print_usage (error_p)
fnotice (file, " -f, --function-summaries Output summaries for each function\n");
fnotice (file, " -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
fnotice (file, " -p, --preserve-paths Preserve all pathname components\n");
fnotice (file, " -u, --unconditional-branches Show unconditional branch counts too\n");
fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
bug_report_url);
exit (status);
@ -365,6 +432,7 @@ static const struct option options[] =
{
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'v' },
{ "all-blocks", no_argument, NULL, 'a' },
{ "branch-probabilities", no_argument, NULL, 'b' },
{ "branch-counts", no_argument, NULL, 'c' },
{ "no-output", no_argument, NULL, 'n' },
@ -373,6 +441,7 @@ static const struct option options[] =
{ "preserve-paths", no_argument, NULL, 'p' },
{ "object-directory", required_argument, NULL, 'o' },
{ "object-file", required_argument, NULL, 'o' },
{ "unconditional-branches", no_argument, NULL, 'u' },
};
/* Process args, return index to first non-arg. */
@ -384,30 +453,30 @@ process_args (argc, argv)
{
int opt;
while ((opt = getopt_long (argc, argv, "hvbclnfo:p", options, NULL)) != -1)
while ((opt = getopt_long (argc, argv, "abcfhlno:puv", options, NULL)) != -1)
{
switch (opt)
{
case 'h':
print_usage (false);
/* print_usage will exit. */
case 'v':
print_version ();
/* print_version will exit. */
case 'a':
flag_all_blocks = 1;
break;
case 'b':
flag_branches = 1;
break;
case 'c':
flag_counts = 1;
break;
case 'n':
flag_gcov_file = 0;
case 'f':
flag_function_summary = 1;
break;
case 'h':
print_usage (false);
/* print_usage will exit. */
case 'l':
flag_long_names = 1;
break;
case 'f':
flag_function_summary = 1;
case 'n':
flag_gcov_file = 0;
break;
case 'o':
object_directory = optarg;
@ -415,6 +484,12 @@ process_args (argc, argv)
case 'p':
flag_preserve_paths = 1;
break;
case 'u':
flag_unconditional = 1;
break;
case 'v':
print_version ();
/* print_version will exit. */
default:
print_usage (true);
/* print_usage will exit. */
@ -528,7 +603,6 @@ release_structures ()
arc_n = arc->succ_next;
free (arc);
}
free (block->encoding);
}
free (fn->blocks);
free (fn->counts);
@ -597,6 +671,34 @@ create_file_names (file_name)
return;
}
/* Find or create a source file structure for FILE_NAME. Free
FILE_NAME appropriately */
static source_t *
find_source (file_name)
char *file_name;
{
source_t *src;
for (src = sources; src; src = src->next)
if (!strcmp (file_name, src->name))
{
free (file_name);
break;
}
if (!src)
{
src = (source_t *)xcalloc (1, sizeof (source_t));
src->name = file_name;
src->coverage.name = file_name;
src->index = sources ? sources->index + 1 : 1;
src->next = sources;
sources = src;
}
return src;
}
/* Read the graph file. Return nonzero on fatal error. */
static int
@ -650,22 +752,45 @@ read_graph_file ()
goto corrupt;
base = gcov_save_position (file);
if (tag == GCOV_TAG_FUNCTION)
{
char *function_name = NULL;
unsigned checksum;
char *function_file = NULL;
unsigned checksum, lineno;
source_t *src;
function_t *probe, *prev;
if (gcov_read_string (file, &function_name, NULL)
|| gcov_read_unsigned (file, &checksum))
|| gcov_read_unsigned (file, &checksum)
|| gcov_read_string (file, &function_file, NULL)
|| gcov_read_unsigned (file, &lineno))
goto corrupt;
src = find_source (function_file);
fn = (function_t *)xcalloc (1, sizeof (function_t));
fn->name = function_name;
fn->checksum = checksum;
fn->src = src;
fn->line = lineno;
fn->next = functions;
functions = fn;
current_tag = tag;
if (lineno >= src->num_lines)
src->num_lines = lineno + 1;
/* Now insert it into the source file's list of
functions. Normally functions will be encountered in
ascending order, so a simple scan is quick. */
for (probe = src->functions, prev = NULL;
probe && probe->line > lineno;
prev = probe, probe = probe->line_next)
continue;
fn->line_next = probe;
if (prev)
prev->line_next = fn;
else
src->functions = fn;
}
else if (fn && tag == GCOV_TAG_BLOCKS)
{
@ -674,9 +799,19 @@ read_graph_file ()
bbg_file_name, fn->name);
else
{
fn->num_blocks = length / 4;
unsigned ix, num_blocks = length / 4;
fn->num_blocks = num_blocks;
fn->blocks
= (block_t *)xcalloc (fn->num_blocks, sizeof (block_t));
for (ix = 0; ix != num_blocks; ix++)
{
unsigned flags;
if (gcov_read_unsigned (file, &flags))
goto corrupt;
fn->blocks[ix].flags = flags;
}
}
}
else if (fn && tag == GCOV_TAG_ARCS)
@ -717,7 +852,24 @@ read_graph_file ()
fn->blocks[dest].pred = arc;
fn->blocks[dest].num_pred++;
arc->is_call = arc->fake;
if (arc->fake)
{
if (src)
{
/* Exceptional exit from this function, the
source block must be a call. */
fn->blocks[src].is_call_site = 1;
arc->is_call_non_return = 1;
}
else
{
/* Non-local return from a callee of this
function. The destination block is a catch or
setjmp. */
arc->is_nonlocal_return = 1;
fn->blocks[dest].is_nonlocal_return = 1;
}
}
if (!arc->on_tree)
fn->num_counts++;
@ -731,7 +883,7 @@ read_graph_file ()
if (gcov_read_unsigned (file, &blockno)
|| blockno >= fn->num_blocks
|| fn->blocks[blockno].encoding)
|| fn->blocks[blockno].u.line.encoding)
goto corrupt;
for (ix = 0; ; )
@ -759,28 +911,15 @@ read_graph_file ()
goto corrupt;
if (!file_name)
break;
for (src = sources; src; src = src->next)
if (!strcmp (file_name, src->name))
{
free (file_name);
break;
}
if (!src)
{
src = (source_t *)xcalloc (1, sizeof (source_t));
src->name = file_name;
src->coverage.name = file_name;
src->index = sources ? sources->index + 1 : 1;
src->next = sources;
sources = src;
}
src = find_source (file_name);
line_nos[ix++] = 0;
line_nos[ix++] = src->index;
}
}
fn->blocks[blockno].encoding = line_nos;
fn->blocks[blockno].num_encodings = ix;
fn->blocks[blockno].u.line.encoding = line_nos;
fn->blocks[blockno].u.line.num = ix;
}
else if (current_tag && !GCOV_TAG_IS_SUBTAG (current_tag, tag))
{
@ -906,7 +1045,15 @@ read_count_file ()
goto cleanup;
}
base = gcov_save_position (file);
if (tag == GCOV_TAG_FUNCTION)
if (tag == GCOV_TAG_OBJECT_SUMMARY)
{
if (gcov_read_summary (file, &object_summary))
goto corrupt;
}
else if (tag == GCOV_TAG_PROGRAM_SUMMARY
|| tag == GCOV_TAG_INCORRECT_SUMMARY)
program_count++;
else if (tag == GCOV_TAG_FUNCTION)
{
unsigned checksum;
struct function_info *fn_n = functions;
@ -977,6 +1124,7 @@ solve_flow_graph (fn)
unsigned ix;
arc_t *arc;
gcov_type *count_ptr = fn->counts;
block_t *blk;
block_t *valid_blocks = NULL; /* valid, but unpropagated blocks. */
block_t *invalid_blocks = NULL; /* invalid, but inferable blocks. */
@ -1004,25 +1152,50 @@ solve_flow_graph (fn)
/* Propagate the measured counts, this must be done in the same
order as the code in profile.c */
for (ix = 0; ix != fn->num_blocks; ix++)
for (ix = 0, blk = fn->blocks; ix != fn->num_blocks; ix++, blk++)
{
block_t const *prev_dst = NULL;
int out_of_order = 0;
int non_fake_succ = 0;
for (arc = fn->blocks[ix].succ; arc; arc = arc->succ_next)
for (arc = blk->succ; arc; arc = arc->succ_next)
{
if (!arc->fake)
non_fake_succ++;
if (!arc->on_tree)
{
if (count_ptr)
arc->count = *count_ptr++;
arc->count_valid = 1;
fn->blocks[ix].num_succ--;
blk->num_succ--;
arc->dst->num_pred--;
}
if (prev_dst && prev_dst > arc->dst)
out_of_order = 1;
prev_dst = arc->dst;
}
if (non_fake_succ == 1)
{
/* If there is only one non-fake exit, it is an
unconditional branch. */
for (arc = blk->succ; arc; arc = arc->succ_next)
if (!arc->fake)
{
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;
}
}
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
@ -1030,7 +1203,7 @@ solve_flow_graph (fn)
smart sort. */
if (out_of_order)
{
arc_t *start = fn->blocks[ix].succ;
arc_t *start = blk->succ;
unsigned changes = 1;
while (changes)
@ -1058,20 +1231,18 @@ solve_flow_graph (fn)
}
}
}
fn->blocks[ix].succ = start;
blk->succ = start;
}
/* Place it on the invalid chain, it will be ignored if that's
wrong. */
fn->blocks[ix].invalid_chain = 1;
fn->blocks[ix].chain = invalid_blocks;
invalid_blocks = &fn->blocks[ix];
blk->invalid_chain = 1;
blk->chain = invalid_blocks;
invalid_blocks = blk;
}
while (invalid_blocks || valid_blocks)
{
block_t *blk;
while ((blk = invalid_blocks))
{
gcov_type total = 0;
@ -1196,13 +1367,13 @@ add_branch_counts (coverage, arc)
coverage_t *coverage;
const arc_t *arc;
{
if (arc->is_call)
if (arc->is_call_non_return)
{
coverage->calls++;
if (arc->src->count)
coverage->calls_executed++;
}
else
else if (!arc->is_unconditional)
{
coverage->branches++;
if (arc->src->count)
@ -1374,7 +1545,7 @@ make_gcov_file_name (input_name, src_name)
static void
add_line_counts (coverage, fn)
coverage_t *coverage;
const function_t *fn;
function_t *fn;
{
unsigned ix;
line_t *line = NULL; /* this is propagated from one iteration to the
@ -1383,13 +1554,16 @@ add_line_counts (coverage, fn)
/* Scan each basic block. */
for (ix = 0; ix != fn->num_blocks; ix++)
{
const block_t *block = &fn->blocks[ix];
block_t *block = &fn->blocks[ix];
unsigned *encoding;
const source_t *src = NULL;
unsigned jx;
line_t *first_line = NULL;
for (jx = 0, encoding = block->encoding;
jx != block->num_encodings; jx++, encoding++)
if (block->count && ix && ix + 1 != fn->num_blocks)
fn->blocks_executed++;
for (jx = 0, encoding = block->u.line.encoding;
jx != block->u.line.num; jx++, encoding++)
if (!*encoding)
{
unsigned src_n = *++encoding;
@ -1406,26 +1580,38 @@ add_line_counts (coverage, fn)
{
if (!line->exists)
coverage->lines++;
if (!line->count && block->count)
if (!line->count && block->count)
coverage->lines_executed++;
}
line->exists = 1;
line->count += block->count;
if (!first_line)
first_line = line;
}
if (line && flag_branches)
free (block->u.line.encoding);
block->u.span.root = NULL;
if (!first_line)
first_line = line;
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];
block->chain = first_line->u.blocks;
first_line->u.blocks = block;
}
else if (flag_branches)
{
arc_t *arc;
for (arc = block->succ; arc; arc = arc->succ_next)
{
/* Ignore fall through arcs as they aren't really branches. */
if (arc->fall_through)
continue;
arc->line_next = line->branches;
line->branches = arc;
if (coverage)
arc->line_next = line->u.branches;
line->u.branches = arc;
if (coverage && !arc->is_unconditional)
add_branch_counts (coverage, arc);
}
}
@ -1441,22 +1627,123 @@ accumulate_line_counts (src)
source_t *src;
{
line_t *line;
function_t *fn, *fn_p, *fn_n;
unsigned ix;
/* Reverse the function order. */
for (fn = src->functions, fn_p = NULL; fn;
fn_p = fn, fn = fn_n)
{
fn_n = fn->line_next;
fn->line_next = fn_p;
}
src->functions = fn_p;
for (ix = src->num_lines, line = src->lines; ix--; line++)
{
arc_t *arc, *arc_p, *arc_n;
/* Total and reverse the branch information. */
for (arc = line->branches, arc_p = NULL; arc; arc_p = arc, arc = arc_n)
if (!flag_all_blocks)
{
arc_n = arc->line_next;
arc->line_next = arc_p;
add_branch_counts (&src->coverage, arc);
arc_t *arc, *arc_p, *arc_n;
/* Total and reverse the branch information. */
for (arc = line->u.branches, arc_p = NULL; arc;
arc_p = arc, arc = arc_n)
{
arc_n = arc->line_next;
arc->line_next = arc_p;
add_branch_counts (&src->coverage, arc);
}
line->u.branches = arc_p;
}
line->branches = arc_p;
else if (line->u.blocks)
{
/* 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. */
block_t *block, *block_p, *block_n;
int changes = 1;
gcov_type count = 0;
/* Reverse the block information */
for (block = line->u.blocks, block_p = NULL; block;
block_p = block, block = block_n)
{
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;
}
line->u.blocks = block_p;
while (changes)
{
changes = 0;
for (block = line->u.blocks; block; block = block->chain)
{
arc_t *arc;
for (arc = block->succ; arc; arc = arc->succ_next)
{
block_t *dst = arc->dst;
if (!dst->u.span.root)
/* Not on this line. */;
else if (dst->u.span.root == block->u.span.root)
/* Same spanning tree. */;
else
{
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.root)
{
root = dst->u.span.root;
dst_root = block->u.span.root;
}
dst->u.span.root = root;
root->u.span.siblings += 1 + dst->u.span.siblings;
if (dst->u.span.siblings)
{
block_t *dst_sib;
dst->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;
}
}
}
}
/* 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)
{
if (!arc->local_span)
count += arc->count;
if (flag_branches)
add_branch_counts (&src->coverage, arc);
}
block->u.span.root = NULL;
}
line->count = count;
}
if (line->exists)
{
src->coverage.lines++;
@ -1466,6 +1753,50 @@ accumulate_line_counts (src)
}
}
/* Ouput information about ARC number IX. Returns non-zero if
anything is output. */
static int
output_branch_count (gcov_file, ix, arc)
FILE *gcov_file;
int ix;
const arc_t *arc;
{
if (arc->is_call_non_return)
{
if (arc->src->count)
{
fnotice (gcov_file, "call %2d returned %s\n", ix,
format_gcov (arc->src->count - arc->count,
arc->src->count, -flag_counts));
}
else
fnotice (gcov_file, "call %2d never executed\n", ix);
}
else if (!arc->is_unconditional)
{
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)" : "");
else
fnotice (gcov_file, "branch %2d never executed\n", ix);
}
else if (flag_unconditional && !arc->src->is_call_site)
{
if (arc->src->count)
fnotice (gcov_file, "unconditional %2d taken %s\n", ix,
format_gcov (arc->count, arc->src->count, -flag_counts));
else
fnotice (gcov_file, "unconditional %2d never executed\n", ix);
}
else
return 0;
return 1;
}
/* Read in the source file one line at a time, and output that line to
the gcov file preceded by its execution count and other
information. */
@ -1480,10 +1811,13 @@ output_lines (gcov_file, src)
const line_t *line; /* current line info ptr. */
char string[STRING_SIZE]; /* line buffer. */
char const *retval = ""; /* status of source file reading. */
function_t *fn = src->functions;
fprintf (gcov_file, "%9s:%5d:Source:%s\n", "-", 0, src->name);
fprintf (gcov_file, "%9s:%5d:Graph:%s\n", "-", 0, bbg_file_name);
fprintf (gcov_file, "%9s:%5d:Data:%s\n", "-", 0, da_file_name);
fprintf (gcov_file, "%9s:%5d:Runs:%u\n", "-", 0, object_summary.runs);
fprintf (gcov_file, "%9s:%5d:Programs:%u\n", "-", 0, program_count);
source_file = fopen (src->name, "r");
if (!source_file)
@ -1508,6 +1842,25 @@ output_lines (gcov_file, src)
for (line_num = 1, line = &src->lines[line_num];
line_num < src->num_lines; line_num++, line++)
{
for (; fn && fn->line == line_num; fn = fn->line_next)
{
arc_t *arc = fn->blocks[fn->num_blocks - 1].pred;
gcov_type return_count = fn->blocks[fn->num_blocks - 1].count;
for (; arc; arc = arc->pred_next)
if (arc->fake)
return_count -= arc->count;
fprintf (gcov_file, "function %s", fn->name);
fprintf (gcov_file, " called %s",
format_gcov (fn->blocks[0].count, 0, -1));
fprintf (gcov_file, " returned %s",
format_gcov (return_count, fn->blocks[0].count, 0));
fprintf (gcov_file, " blocks executed %s",
format_gcov (fn->blocks_executed, fn->num_blocks - 2, 0));
fprintf (gcov_file, "\n");
}
/* For lines which don't exist in the .bb file, print '-' before
the source line. For lines which exist but were never
executed, print '#####' before the source line. Otherwise,
@ -1535,36 +1888,33 @@ output_lines (gcov_file, src)
}
if (!retval)
fputs ("??\n", gcov_file);
if (flag_branches)
if (flag_all_blocks)
{
block_t *block;
int ix, jx;
for (ix = jx = 0, block = line->u.blocks; block;
block = block->chain)
{
arc_t *arc;
if (!block->is_call_site)
fprintf (gcov_file, "%9s:%5u-block %2d\n",
!line->exists ? "-" : !block->count ? "$$$$$"
: 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);
}
}
else if (flag_branches)
{
int ix;
arc_t *arc;
for (ix = 0, arc = line->branches; arc; arc = arc->line_next, ix++)
{
if (arc->is_call)
{
if (arc->src->count)
fnotice
(gcov_file, "call %2d returns %s\n", ix,
format_gcov (arc->src->count - arc->count,
arc->src->count,
-flag_counts));
else
fnotice (gcov_file, "call %2d never executed\n", ix);
}
else
{
if (arc->src->count)
fnotice
(gcov_file, "branch %2d taken %s\n", ix,
format_gcov (arc->count, arc->src->count,
-flag_counts));
else
fnotice (gcov_file, "branch %2d never executed\n", ix);
}
}
for (ix = 0, arc = line->u.branches; arc; arc = arc->line_next)
ix += output_branch_count (gcov_file, ix, arc);
}
}

View File

@ -926,7 +926,7 @@ branch_prob ()
unsigned num_edges, ignored_edges;
struct edge_list *el;
const char *name = IDENTIFIER_POINTER
(DECL_ASSEMBLER_NAME (current_function_decl));
(DECL_ASSEMBLER_NAME (current_function_decl));
profile_info.current_function_cfg_checksum = compute_checksum ();
for (i = 0; i < profile_info.n_sections; i++)
@ -1086,6 +1086,8 @@ branch_prob ()
if (flag_test_coverage && bbg_file)
{
long offset;
const char *file = DECL_SOURCE_FILE (current_function_decl);
unsigned line = DECL_SOURCE_LINE (current_function_decl);
/* Announce function */
if (gcov_write_unsigned (bbg_file, GCOV_TAG_FUNCTION)
@ -1094,6 +1096,8 @@ branch_prob ()
strlen (name))
|| gcov_write_unsigned (bbg_file,
profile_info.current_function_cfg_checksum)
|| gcov_write_string (bbg_file, file, strlen (file))
|| gcov_write_unsigned (bbg_file, line)
|| gcov_write_length (bbg_file, offset))
goto bbg_error;

View File

@ -1,3 +1,8 @@
2003-03-31 Nathan Sidwell <nathan@codesourcery.com>
* lib/gcov.exp: Adjust call return testing strings.
* g77.dg/gcov/gcov-1.f: Don't expect unconditional branches.
2003-03-31 Roger Sayle <roger@eyesopen.com>
* gcc.dg/builtins-3.c: Add new tests for sin and cos.

View File

@ -118,9 +118,7 @@ C Test simple GOTO.
if (f .ne. 0) goto 100 ! count(2)
! branch(end)
gt1 = 1 ! count(1)
! branch(100)
goto 101 ! count(1)
! branch(end)
100 gt1 = 2 ! count(1)
101 continue ! count(2)
end
@ -136,9 +134,7 @@ C Test simple GOTO again, this time out of a DO loop.
if (i .eq. f) goto 100 ! count(19)
end do
gt2 = 4 ! count(1)
! branch(100)
goto 101 ! count(1)
! branch(end)
100 gt2 = 8 ! count(1)
101 continue ! count(2)
end
@ -149,17 +145,13 @@ C Test computed GOTO.
integer i
goto (101, 102, 103, 104), i ! count(2)
gt3 = 8 ! count(1)
! branch(100)
goto 105 ! count(1)
! branch(end)
101 gt3 = 1024
goto 105
102 gt3 = 2048
goto 105
103 gt3 = 16 ! count(1)
! branch(100)
goto 105 ! count(1)
! branch(end)
104 gt3 = 4096
goto 105
105 gt3 = gt3 * 2 ! count(2)

View File

@ -168,7 +168,7 @@ proc verify-calls { testcase file } {
set n 0
while { [gets $fd line] >= 0 } {
regexp "^\[^:\]+: *(\[0-9\]+):" "$line" all n
if [regexp "returns" $line] {
if [regexp "return" $line] {
verbose "Processing returns line $n: $line" 3
if [regexp "returns\\((\[0-9 \]+)\\)" "$line" all new_shouldbe] {
# All percentages in the current list should have been seen.
@ -179,12 +179,12 @@ proc verify-calls { testcase file } {
}
# Record the percentages to check for.
set shouldbe $new_shouldbe
} elseif [regexp "call +\[0-9\]+ returns (-\[0-9\]+)%" "$line" \
} elseif [regexp "call +\[0-9\]+ returned (-\[0-9\]+)%" "$line" \
all returns] {
# Percentages should never be negative.
fail "$n: negative percentage: $returns"
incr failed
} elseif [regexp "call +\[0-9\]+ returns (\[0-9\]+)%" "$line" \
} elseif [regexp "call +\[0-9\]+ returned (\[0-9\]+)%" "$line" \
all returns] {
# For branches we check that percentages are not greater than
# 100 but call return percentages can be, as for setjmp(), so