Commit 27283c73 by Nathan Sidwell Committed by Nathan Sidwell

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
parent 212d9313
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> 2003-03-31 Kazu Hirata <kazu@cs.umass.edu>
* config/h8300/h8300.md: Organize peephole2's that trasform * config/h8300/h8300.md: Organize peephole2's that trasform
......
...@@ -120,6 +120,7 @@ gcov @r{[}@var{options}@r{]} @var{sourcefile} ...@@ -120,6 +120,7 @@ gcov @r{[}@var{options}@r{]} @var{sourcefile}
@ignore @ignore
@c man begin SYNOPSIS @c man begin SYNOPSIS
gcov [@option{-v}|@option{--version}] [@option{-h}|@option{--help}] gcov [@option{-v}|@option{--version}] [@option{-h}|@option{--help}]
[@option{-a}|@option{--all-blocks}]
[@option{-b}|@option{--branch-probabilities}] [@option{-b}|@option{--branch-probabilities}]
[@option{-c}|@option{--branch-counts}] [@option{-c}|@option{--branch-counts}]
[@option{-n}|@option{--no-output}] [@option{-n}|@option{--no-output}]
...@@ -127,6 +128,7 @@ gcov [@option{-v}|@option{--version}] [@option{-h}|@option{--help}] ...@@ -127,6 +128,7 @@ gcov [@option{-v}|@option{--version}] [@option{-h}|@option{--help}]
[@option{-p}|@option{--preserve-paths}] [@option{-p}|@option{--preserve-paths}]
[@option{-f}|@option{--function-summaries}] [@option{-f}|@option{--function-summaries}]
[@option{-o}|@option{--object-directory} @var{directory|file}] @var{sourcefile} [@option{-o}|@option{--object-directory} @var{directory|file}] @var{sourcefile}
[@option{-u}|@option{--unconditional-branches}]
@c man end @c man end
@c man begin SEEALSO @c man begin SEEALSO
gpl(7), gfdl(7), fsf-funding(7), gcc(1) and the Info entry for @file{gcc}. 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. ...@@ -145,11 +147,23 @@ exit without doing any further processing.
Display the @command{gcov} version number (on the standard output), Display the @command{gcov} version number (on the standard output),
and exit without doing any further processing. 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 @item -b
@itemx --branch-probabilities @itemx --branch-probabilities
Write branch frequencies to the output file, and write branch summary Write branch frequencies to the output file, and write branch summary
info to the standard output. This option allows you to see how often 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 @item -c
@itemx --branch-counts @itemx --branch-counts
...@@ -192,6 +206,11 @@ source file name, without its extension. If a file is specified here, ...@@ -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 the data files are named after that file, without its extension. If this
option is not supplied, it defaults to the current directory. 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 @end table
Gcov should be run with the current directory the same as that when you Gcov should be run with the current directory the same as that when you
...@@ -248,26 +267,68 @@ Here is a sample: ...@@ -248,26 +267,68 @@ Here is a sample:
@smallexample @smallexample
-: 0:Source:tmp.c -: 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++)
10: 10: total += i;
-: 11:
1: 12: if (total != 45)
#####: 13: printf ("Failure\n");
-: 14: else
1: 15: printf ("Success\n");
1: 16: return 0;
-: 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> -: 1:#include <stdio.h>
-: 2: -: 2:
-: 3:int main (void) -: 3:int main (void)
function main called 1 returned 1 blocks executed 75%
1: 4:@{ 1: 4:@{
1: 4-block 0
1: 5: int i, total; 1: 5: int i, total;
-: 6: -: 6:
1: 7: total = 0; 1: 7: total = 0;
-: 8: -: 8:
11: 9: for (i = 0; i < 10; i++) 11: 9: for (i = 0; i < 10; i++)
11: 9-block 0
10: 10: total += i; 10: 10: total += i;
10: 10-block 0
-: 11: -: 11:
1: 12: if (total != 45) 1: 12: if (total != 45)
1: 12-block 0
#####: 13: printf ("Failure\n"); #####: 13: printf ("Failure\n");
$$$$$: 13-block 0
-: 14: else -: 14: else
1: 15: printf ("Success\n"); 1: 15: printf ("Success\n");
1: 15-block 0
1: 16: return 0; 1: 16: return 0;
1: 17:@} 1: 16-block 0
-: 17:@}
@end smallexample @end smallexample
As you can see, line 13 contains a basic block that was not executed.
@need 450 @need 450
When you use the @option{-b} option, your output looks like this: 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: ...@@ -284,31 +345,34 @@ Here is a sample of a resulting @file{tmp.c.gcov} file:
@smallexample @smallexample
-: 0:Source:tmp.c -: 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> -: 1:#include <stdio.h>
-: 2: -: 2:
-: 3:int main (void) -: 3:int main (void)
function main called 1 returned 1 blocks executed 75%
1: 4:@{ 1: 4:@{
1: 5: int i, total; 1: 5: int i, total;
-: 6: -: 6:
1: 7: total = 0; 1: 7: total = 0;
-: 8: -: 8:
11: 9: for (i = 0; i < 10; i++) 11: 9: for (i = 0; i < 10; i++)
branch 0: taken 90% branch 0 taken 91% (fallthrough)
branch 1: taken 100% branch 1 taken 9%
branch 2: taken 100%
10: 10: total += i; 10: 10: total += i;
-: 11: -: 11:
1: 12: if (total != 45) 1: 12: if (total != 45)
branch 0: taken 100% branch 0 taken 0% (fallthrough)
branch 1 taken 100%
#####: 13: printf ("Failure\n"); #####: 13: printf ("Failure\n");
call 0: never executed call 0 never executed
branch 1: never executed
-: 14: else -: 14: else
1: 15: printf ("Success\n"); 1: 15: printf ("Success\n");
call 0: returns 100% call 0 called 1 returned 100%
1: 16: return 0; 1: 16: return 0;
1: 17:@} -: 17:@}
@end smallexample @end smallexample
For each basic block, a line is printed after the last line of the basic For each basic block, a line is printed after the last line of the basic
......
...@@ -90,6 +90,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA ...@@ -90,6 +90,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
bbg: function-graph* bbg: function-graph*
function-graph: announce_function basic_blocks {arcs | lines}* function-graph: announce_function basic_blocks {arcs | lines}*
announce_function: header string:name int32:checksum announce_function: header string:name int32:checksum
string:source int32:lineno
basic_block: header int32:flags* basic_block: header int32:flags*
arcs: header int32:block_no arc* arcs: header int32:block_no arc*
arc: int32:dest_block int32:flags arc: int32:dest_block int32:flags
...@@ -121,7 +122,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA ...@@ -121,7 +122,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
summary: in32:checksum int32:runs int32:arcs int64:sum int64:max \ summary: in32:checksum int32:runs int32:arcs int64:sum int64:max \
int64:max_sum int64:sum_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 The ARC_COUNTS gives the counter values for those arcs that are
instrumented. The SUMMARY records give information about the whole instrumented. The SUMMARY records give information about the whole
object file and about the whole program. The checksum is used for object file and about the whole program. The checksum is used for
...@@ -195,7 +197,7 @@ typedef long long gcov_type; ...@@ -195,7 +197,7 @@ typedef long long gcov_type;
(GCOV_TAG_MASK (TAG) > GCOV_TAG_MASK (SUB)) (GCOV_TAG_MASK (TAG) > GCOV_TAG_MASK (SUB))
/* Basic block flags. */ /* Basic block flags. */
#define GCOV_BLOCK_UNEXPECTED (1 << 0) #define GCOV_BLOCK_UNEXPECTED (1 << 1)
/* Arc flags. */ /* Arc flags. */
#define GCOV_ARC_ON_TREE (1 << 0) #define GCOV_ARC_ON_TREE (1 << 0)
......
...@@ -69,6 +69,7 @@ typedef HOST_WIDEST_INT gcov_type; ...@@ -69,6 +69,7 @@ typedef HOST_WIDEST_INT gcov_type;
struct function_info; struct function_info;
struct block_info; struct block_info;
struct source_info;
/* Describes an arc between two basic blocks. */ /* Describes an arc between two basic blocks. */
...@@ -86,8 +87,17 @@ typedef struct arc_info ...@@ -86,8 +87,17 @@ typedef struct arc_info
unsigned int fake : 1; unsigned int fake : 1;
unsigned int fall_through : 1; unsigned int fall_through : 1;
/* Arc to a call. */ /* Arc is for a function that abnormally returns. */
unsigned int is_call : 1; 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. */ /* Next branch on line. */
struct arc_info *line_next; struct arc_info *line_next;
...@@ -112,17 +122,39 @@ typedef struct block_info ...@@ -112,17 +122,39 @@ typedef struct block_info
/* Block execution count. */ /* Block execution count. */
gcov_type count; gcov_type count;
unsigned flags : 13;
unsigned count_valid : 1; unsigned count_valid : 1;
unsigned valid_chain : 1; unsigned valid_chain : 1;
unsigned invalid_chain : 1; unsigned invalid_chain : 1;
/* Block is a call instrumenting site. */
unsigned is_call_site : 1;
/* 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 /* Array of line numbers and source files. source files are
introduced by a linenumber of zero, the next 'line number' is the introduced by a linenumber of zero, the next 'line number' is
number of the source file. Always starts with a source file. */ the number of the source file. Always starts with a source
file. */
unsigned *encoding; unsigned *encoding;
unsigned num_encodings; unsigned num;
} line; /* Valid until blocks are linked onto lines */
/* Temporary chain for solving graph. */ 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; struct block_info *chain;
} block_t; } block_t;
...@@ -138,11 +170,19 @@ typedef struct function_info ...@@ -138,11 +170,19 @@ typedef struct function_info
/* Array of basic blocks. */ /* Array of basic blocks. */
block_t *blocks; block_t *blocks;
unsigned num_blocks; unsigned num_blocks;
unsigned blocks_executed;
/* Raw arc coverage counts. */ /* Raw arc coverage counts. */
gcov_type *counts; gcov_type *counts;
unsigned num_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. */ /* Next function. */
struct function_info *next; struct function_info *next;
} function_t; } function_t;
...@@ -170,8 +210,14 @@ typedef struct coverage_info ...@@ -170,8 +210,14 @@ typedef struct coverage_info
typedef struct line_info typedef struct line_info
{ {
gcov_type count; /* execution count */ gcov_type count; /* execution count */
union
{
arc_t *branches; /* branches from blocks that end on this arc_t *branches; /* branches from blocks that end on this
line. */ 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; unsigned exists : 1;
} line_t; } line_t;
...@@ -190,6 +236,10 @@ typedef struct source_info ...@@ -190,6 +236,10 @@ typedef struct source_info
coverage_t coverage; coverage_t coverage;
/* Functions in this source file. These are in ascending line
number order. */
function_t *functions;
/* Next source file. */ /* Next source file. */
struct source_info *next; struct source_info *next;
} source_t; } source_t;
...@@ -202,6 +252,11 @@ static function_t *functions; ...@@ -202,6 +252,11 @@ static function_t *functions;
static source_t *sources; static source_t *sources;
/* This holds data summary information. */
static struct gcov_summary object_summary;
static unsigned program_count;
/* Modification time of graph file. */ /* Modification time of graph file. */
static time_t bbg_file_time; static time_t bbg_file_time;
...@@ -218,6 +273,9 @@ static char *da_file_name; ...@@ -218,6 +273,9 @@ static char *da_file_name;
static int flag_branches = 0; 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 /* Output a gcov file if this is true. This is on by default, and can
be turned off by the -n option. */ be turned off by the -n option. */
...@@ -229,6 +287,11 @@ static int flag_gcov_file = 1; ...@@ -229,6 +287,11 @@ static int flag_gcov_file = 1;
static int flag_long_names = 0; 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. */ /* Output summary info for each function. */
static int flag_function_summary = 0; static int flag_function_summary = 0;
...@@ -256,14 +319,16 @@ static void print_usage PARAMS ((int)) ATTRIBUTE_NORETURN; ...@@ -256,14 +319,16 @@ static void print_usage PARAMS ((int)) ATTRIBUTE_NORETURN;
static void print_version PARAMS ((void)) ATTRIBUTE_NORETURN; static void print_version PARAMS ((void)) ATTRIBUTE_NORETURN;
static void process_file PARAMS ((const char *)); static void process_file PARAMS ((const char *));
static void create_file_names 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_graph_file PARAMS ((void));
static int read_count_file PARAMS ((void)); static int read_count_file PARAMS ((void));
static void solve_flow_graph PARAMS ((function_t *)); static void solve_flow_graph PARAMS ((function_t *));
static void add_branch_counts PARAMS ((coverage_t *, const arc_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 void function_summary PARAMS ((const coverage_t *, const char *));
static const char *format_gcov PARAMS ((gcov_type, gcov_type, int)); static const char *format_gcov PARAMS ((gcov_type, gcov_type, int));
static void accumulate_line_counts PARAMS ((source_t *)); 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 void output_lines PARAMS ((FILE *, const source_t *));
static char *make_gcov_file_name PARAMS ((const char *, const char *)); static char *make_gcov_file_name PARAMS ((const char *, const char *));
static void release_structures PARAMS ((void)); static void release_structures PARAMS ((void));
...@@ -328,6 +393,7 @@ print_usage (error_p) ...@@ -328,6 +393,7 @@ print_usage (error_p)
fnotice (file, "Print code coverage information.\n\n"); fnotice (file, "Print code coverage information.\n\n");
fnotice (file, " -h, --help Print this help, then exit\n"); fnotice (file, " -h, --help Print this help, then exit\n");
fnotice (file, " -v, --version Print version number, 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, " -b, --branch-probabilities Include branch probabilities in output\n");
fnotice (file, " -c, --branch-counts Given counts of branches taken\n\ fnotice (file, " -c, --branch-counts Given counts of branches taken\n\
rather than percentages\n"); rather than percentages\n");
...@@ -337,6 +403,7 @@ print_usage (error_p) ...@@ -337,6 +403,7 @@ print_usage (error_p)
fnotice (file, " -f, --function-summaries Output summaries for each function\n"); 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, " -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, " -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", fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
bug_report_url); bug_report_url);
exit (status); exit (status);
...@@ -365,6 +432,7 @@ static const struct option options[] = ...@@ -365,6 +432,7 @@ static const struct option options[] =
{ {
{ "help", no_argument, NULL, 'h' }, { "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'v' }, { "version", no_argument, NULL, 'v' },
{ "all-blocks", no_argument, NULL, 'a' },
{ "branch-probabilities", no_argument, NULL, 'b' }, { "branch-probabilities", no_argument, NULL, 'b' },
{ "branch-counts", no_argument, NULL, 'c' }, { "branch-counts", no_argument, NULL, 'c' },
{ "no-output", no_argument, NULL, 'n' }, { "no-output", no_argument, NULL, 'n' },
...@@ -373,6 +441,7 @@ static const struct option options[] = ...@@ -373,6 +441,7 @@ static const struct option options[] =
{ "preserve-paths", no_argument, NULL, 'p' }, { "preserve-paths", no_argument, NULL, 'p' },
{ "object-directory", required_argument, NULL, 'o' }, { "object-directory", required_argument, NULL, 'o' },
{ "object-file", required_argument, NULL, 'o' }, { "object-file", required_argument, NULL, 'o' },
{ "unconditional-branches", no_argument, NULL, 'u' },
}; };
/* Process args, return index to first non-arg. */ /* Process args, return index to first non-arg. */
...@@ -384,30 +453,30 @@ process_args (argc, argv) ...@@ -384,30 +453,30 @@ process_args (argc, argv)
{ {
int opt; 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) switch (opt)
{ {
case 'h': case 'a':
print_usage (false); flag_all_blocks = 1;
/* print_usage will exit. */ break;
case 'v':
print_version ();
/* print_version will exit. */
case 'b': case 'b':
flag_branches = 1; flag_branches = 1;
break; break;
case 'c': case 'c':
flag_counts = 1; flag_counts = 1;
break; break;
case 'n': case 'f':
flag_gcov_file = 0; flag_function_summary = 1;
break; break;
case 'h':
print_usage (false);
/* print_usage will exit. */
case 'l': case 'l':
flag_long_names = 1; flag_long_names = 1;
break; break;
case 'f': case 'n':
flag_function_summary = 1; flag_gcov_file = 0;
break; break;
case 'o': case 'o':
object_directory = optarg; object_directory = optarg;
...@@ -415,6 +484,12 @@ process_args (argc, argv) ...@@ -415,6 +484,12 @@ process_args (argc, argv)
case 'p': case 'p':
flag_preserve_paths = 1; flag_preserve_paths = 1;
break; break;
case 'u':
flag_unconditional = 1;
break;
case 'v':
print_version ();
/* print_version will exit. */
default: default:
print_usage (true); print_usage (true);
/* print_usage will exit. */ /* print_usage will exit. */
...@@ -528,7 +603,6 @@ release_structures () ...@@ -528,7 +603,6 @@ release_structures ()
arc_n = arc->succ_next; arc_n = arc->succ_next;
free (arc); free (arc);
} }
free (block->encoding);
} }
free (fn->blocks); free (fn->blocks);
free (fn->counts); free (fn->counts);
...@@ -597,6 +671,34 @@ create_file_names (file_name) ...@@ -597,6 +671,34 @@ create_file_names (file_name)
return; 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. */ /* Read the graph file. Return nonzero on fatal error. */
static int static int
...@@ -654,18 +756,41 @@ read_graph_file () ...@@ -654,18 +756,41 @@ read_graph_file ()
if (tag == GCOV_TAG_FUNCTION) if (tag == GCOV_TAG_FUNCTION)
{ {
char *function_name = NULL; 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) 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; goto corrupt;
src = find_source (function_file);
fn = (function_t *)xcalloc (1, sizeof (function_t)); fn = (function_t *)xcalloc (1, sizeof (function_t));
fn->name = function_name; fn->name = function_name;
fn->checksum = checksum; fn->checksum = checksum;
fn->src = src;
fn->line = lineno;
fn->next = functions; fn->next = functions;
functions = fn; functions = fn;
current_tag = tag; 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) else if (fn && tag == GCOV_TAG_BLOCKS)
{ {
...@@ -674,9 +799,19 @@ read_graph_file () ...@@ -674,9 +799,19 @@ read_graph_file ()
bbg_file_name, fn->name); bbg_file_name, fn->name);
else else
{ {
fn->num_blocks = length / 4; unsigned ix, num_blocks = length / 4;
fn->num_blocks = num_blocks;
fn->blocks fn->blocks
= (block_t *)xcalloc (fn->num_blocks, sizeof (block_t)); = (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) else if (fn && tag == GCOV_TAG_ARCS)
...@@ -717,7 +852,24 @@ read_graph_file () ...@@ -717,7 +852,24 @@ read_graph_file ()
fn->blocks[dest].pred = arc; fn->blocks[dest].pred = arc;
fn->blocks[dest].num_pred++; 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) if (!arc->on_tree)
fn->num_counts++; fn->num_counts++;
...@@ -731,7 +883,7 @@ read_graph_file () ...@@ -731,7 +883,7 @@ read_graph_file ()
if (gcov_read_unsigned (file, &blockno) if (gcov_read_unsigned (file, &blockno)
|| blockno >= fn->num_blocks || blockno >= fn->num_blocks
|| fn->blocks[blockno].encoding) || fn->blocks[blockno].u.line.encoding)
goto corrupt; goto corrupt;
for (ix = 0; ; ) for (ix = 0; ; )
...@@ -759,28 +911,15 @@ read_graph_file () ...@@ -759,28 +911,15 @@ read_graph_file ()
goto corrupt; goto corrupt;
if (!file_name) if (!file_name)
break; break;
for (src = sources; src; src = src->next) src = find_source (file_name);
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;
}
line_nos[ix++] = 0; line_nos[ix++] = 0;
line_nos[ix++] = src->index; line_nos[ix++] = src->index;
} }
} }
fn->blocks[blockno].encoding = line_nos; fn->blocks[blockno].u.line.encoding = line_nos;
fn->blocks[blockno].num_encodings = ix; fn->blocks[blockno].u.line.num = ix;
} }
else if (current_tag && !GCOV_TAG_IS_SUBTAG (current_tag, tag)) else if (current_tag && !GCOV_TAG_IS_SUBTAG (current_tag, tag))
{ {
...@@ -906,7 +1045,15 @@ read_count_file () ...@@ -906,7 +1045,15 @@ read_count_file ()
goto cleanup; goto cleanup;
} }
base = gcov_save_position (file); 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; unsigned checksum;
struct function_info *fn_n = functions; struct function_info *fn_n = functions;
...@@ -977,6 +1124,7 @@ solve_flow_graph (fn) ...@@ -977,6 +1124,7 @@ solve_flow_graph (fn)
unsigned ix; unsigned ix;
arc_t *arc; arc_t *arc;
gcov_type *count_ptr = fn->counts; gcov_type *count_ptr = fn->counts;
block_t *blk;
block_t *valid_blocks = NULL; /* valid, but unpropagated blocks. */ block_t *valid_blocks = NULL; /* valid, but unpropagated blocks. */
block_t *invalid_blocks = NULL; /* invalid, but inferable blocks. */ block_t *invalid_blocks = NULL; /* invalid, but inferable blocks. */
...@@ -1004,25 +1152,50 @@ solve_flow_graph (fn) ...@@ -1004,25 +1152,50 @@ solve_flow_graph (fn)
/* Propagate the measured counts, this must be done in the same /* Propagate the measured counts, this must be done in the same
order as the code in profile.c */ 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; block_t const *prev_dst = NULL;
int out_of_order = 0; 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 (!arc->on_tree)
{ {
if (count_ptr) if (count_ptr)
arc->count = *count_ptr++; arc->count = *count_ptr++;
arc->count_valid = 1; arc->count_valid = 1;
fn->blocks[ix].num_succ--; blk->num_succ--;
arc->dst->num_pred--; arc->dst->num_pred--;
} }
if (prev_dst && prev_dst > arc->dst) if (prev_dst && prev_dst > arc->dst)
out_of_order = 1; out_of_order = 1;
prev_dst = arc->dst; 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 /* Sort the successor arcs into ascending dst order. profile.c
normally produces arcs in the right order, but sometimes with normally produces arcs in the right order, but sometimes with
...@@ -1030,7 +1203,7 @@ solve_flow_graph (fn) ...@@ -1030,7 +1203,7 @@ solve_flow_graph (fn)
smart sort. */ smart sort. */
if (out_of_order) if (out_of_order)
{ {
arc_t *start = fn->blocks[ix].succ; arc_t *start = blk->succ;
unsigned changes = 1; unsigned changes = 1;
while (changes) while (changes)
...@@ -1058,20 +1231,18 @@ solve_flow_graph (fn) ...@@ -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 /* Place it on the invalid chain, it will be ignored if that's
wrong. */ wrong. */
fn->blocks[ix].invalid_chain = 1; blk->invalid_chain = 1;
fn->blocks[ix].chain = invalid_blocks; blk->chain = invalid_blocks;
invalid_blocks = &fn->blocks[ix]; invalid_blocks = blk;
} }
while (invalid_blocks || valid_blocks) while (invalid_blocks || valid_blocks)
{ {
block_t *blk;
while ((blk = invalid_blocks)) while ((blk = invalid_blocks))
{ {
gcov_type total = 0; gcov_type total = 0;
...@@ -1196,13 +1367,13 @@ add_branch_counts (coverage, arc) ...@@ -1196,13 +1367,13 @@ add_branch_counts (coverage, arc)
coverage_t *coverage; coverage_t *coverage;
const arc_t *arc; const arc_t *arc;
{ {
if (arc->is_call) if (arc->is_call_non_return)
{ {
coverage->calls++; coverage->calls++;
if (arc->src->count) if (arc->src->count)
coverage->calls_executed++; coverage->calls_executed++;
} }
else else if (!arc->is_unconditional)
{ {
coverage->branches++; coverage->branches++;
if (arc->src->count) if (arc->src->count)
...@@ -1374,7 +1545,7 @@ make_gcov_file_name (input_name, src_name) ...@@ -1374,7 +1545,7 @@ make_gcov_file_name (input_name, src_name)
static void static void
add_line_counts (coverage, fn) add_line_counts (coverage, fn)
coverage_t *coverage; coverage_t *coverage;
const function_t *fn; function_t *fn;
{ {
unsigned ix; unsigned ix;
line_t *line = NULL; /* this is propagated from one iteration to the line_t *line = NULL; /* this is propagated from one iteration to the
...@@ -1383,13 +1554,16 @@ add_line_counts (coverage, fn) ...@@ -1383,13 +1554,16 @@ add_line_counts (coverage, fn)
/* Scan each basic block. */ /* Scan each basic block. */
for (ix = 0; ix != fn->num_blocks; ix++) for (ix = 0; ix != fn->num_blocks; ix++)
{ {
const block_t *block = &fn->blocks[ix]; block_t *block = &fn->blocks[ix];
unsigned *encoding; unsigned *encoding;
const source_t *src = NULL; const source_t *src = NULL;
unsigned jx; unsigned jx;
line_t *first_line = NULL;
for (jx = 0, encoding = block->encoding; if (block->count && ix && ix + 1 != fn->num_blocks)
jx != block->num_encodings; jx++, encoding++) fn->blocks_executed++;
for (jx = 0, encoding = block->u.line.encoding;
jx != block->u.line.num; jx++, encoding++)
if (!*encoding) if (!*encoding)
{ {
unsigned src_n = *++encoding; unsigned src_n = *++encoding;
...@@ -1411,21 +1585,33 @@ add_line_counts (coverage, fn) ...@@ -1411,21 +1585,33 @@ add_line_counts (coverage, fn)
} }
line->exists = 1; line->exists = 1;
line->count += block->count; 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;
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];
if (line && flag_branches) block->chain = first_line->u.blocks;
first_line->u.blocks = block;
}
else if (flag_branches)
{ {
arc_t *arc; arc_t *arc;
for (arc = block->succ; arc; arc = arc->succ_next) for (arc = block->succ; arc; arc = arc->succ_next)
{ {
/* Ignore fall through arcs as they aren't really branches. */ arc->line_next = line->u.branches;
if (arc->fall_through) line->u.branches = arc;
continue; if (coverage && !arc->is_unconditional)
arc->line_next = line->branches;
line->branches = arc;
if (coverage)
add_branch_counts (coverage, arc); add_branch_counts (coverage, arc);
} }
} }
...@@ -1441,21 +1627,122 @@ accumulate_line_counts (src) ...@@ -1441,21 +1627,122 @@ accumulate_line_counts (src)
source_t *src; source_t *src;
{ {
line_t *line; line_t *line;
function_t *fn, *fn_p, *fn_n;
unsigned ix; 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++) for (ix = src->num_lines, line = src->lines; ix--; line++)
{ {
if (!flag_all_blocks)
{
arc_t *arc, *arc_p, *arc_n; arc_t *arc, *arc_p, *arc_n;
/* Total and reverse the branch information. */ /* Total and reverse the branch information. */
for (arc = line->branches, arc_p = NULL; arc; arc_p = arc, arc = arc_n) for (arc = line->u.branches, arc_p = NULL; arc;
arc_p = arc, arc = arc_n)
{ {
arc_n = arc->line_next; arc_n = arc->line_next;
arc->line_next = arc_p; arc->line_next = arc_p;
add_branch_counts (&src->coverage, arc); add_branch_counts (&src->coverage, arc);
} }
line->branches = arc_p; line->u.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) if (line->exists)
{ {
...@@ -1466,6 +1753,50 @@ accumulate_line_counts (src) ...@@ -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 /* 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 the gcov file preceded by its execution count and other
information. */ information. */
...@@ -1480,10 +1811,13 @@ output_lines (gcov_file, src) ...@@ -1480,10 +1811,13 @@ output_lines (gcov_file, src)
const line_t *line; /* current line info ptr. */ const line_t *line; /* current line info ptr. */
char string[STRING_SIZE]; /* line buffer. */ char string[STRING_SIZE]; /* line buffer. */
char const *retval = ""; /* status of source file reading. */ 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:Source:%s\n", "-", 0, src->name);
fprintf (gcov_file, "%9s:%5d:Graph:%s\n", "-", 0, bbg_file_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: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"); source_file = fopen (src->name, "r");
if (!source_file) if (!source_file)
...@@ -1508,6 +1842,25 @@ output_lines (gcov_file, src) ...@@ -1508,6 +1842,25 @@ output_lines (gcov_file, src)
for (line_num = 1, line = &src->lines[line_num]; for (line_num = 1, line = &src->lines[line_num];
line_num < src->num_lines; line_num++, line++) 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 /* For lines which don't exist in the .bb file, print '-' before
the source line. For lines which exist but were never the source line. For lines which exist but were never
executed, print '#####' before the source line. Otherwise, executed, print '#####' before the source line. Otherwise,
...@@ -1536,35 +1889,32 @@ output_lines (gcov_file, src) ...@@ -1536,35 +1889,32 @@ output_lines (gcov_file, src)
if (!retval) if (!retval)
fputs ("??\n", gcov_file); fputs ("??\n", gcov_file);
if (flag_branches) if (flag_all_blocks)
{ {
int ix; block_t *block;
arc_t *arc; int ix, jx;
for (ix = 0, arc = line->branches; arc; arc = arc->line_next, ix++) for (ix = jx = 0, block = line->u.blocks; block;
{ block = block->chain)
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) arc_t *arc;
fnotice
(gcov_file, "branch %2d taken %s\n", ix, if (!block->is_call_site)
format_gcov (arc->count, arc->src->count, fprintf (gcov_file, "%9s:%5u-block %2d\n",
-flag_counts)); !line->exists ? "-" : !block->count ? "$$$$$"
else : format_gcov (block->count, 0, -1), line_num, ix++);
fnotice (gcov_file, "branch %2d never executed\n", 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->u.branches; arc; arc = arc->line_next)
ix += output_branch_count (gcov_file, ix, arc);
} }
} }
......
...@@ -1086,6 +1086,8 @@ branch_prob () ...@@ -1086,6 +1086,8 @@ branch_prob ()
if (flag_test_coverage && bbg_file) if (flag_test_coverage && bbg_file)
{ {
long offset; long offset;
const char *file = DECL_SOURCE_FILE (current_function_decl);
unsigned line = DECL_SOURCE_LINE (current_function_decl);
/* Announce function */ /* Announce function */
if (gcov_write_unsigned (bbg_file, GCOV_TAG_FUNCTION) if (gcov_write_unsigned (bbg_file, GCOV_TAG_FUNCTION)
...@@ -1094,6 +1096,8 @@ branch_prob () ...@@ -1094,6 +1096,8 @@ branch_prob ()
strlen (name)) strlen (name))
|| gcov_write_unsigned (bbg_file, || gcov_write_unsigned (bbg_file,
profile_info.current_function_cfg_checksum) 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)) || gcov_write_length (bbg_file, offset))
goto bbg_error; goto bbg_error;
......
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> 2003-03-31 Roger Sayle <roger@eyesopen.com>
* gcc.dg/builtins-3.c: Add new tests for sin and cos. * gcc.dg/builtins-3.c: Add new tests for sin and cos.
......
...@@ -118,9 +118,7 @@ C Test simple GOTO. ...@@ -118,9 +118,7 @@ C Test simple GOTO.
if (f .ne. 0) goto 100 ! count(2) if (f .ne. 0) goto 100 ! count(2)
! branch(end) ! branch(end)
gt1 = 1 ! count(1) gt1 = 1 ! count(1)
! branch(100)
goto 101 ! count(1) goto 101 ! count(1)
! branch(end)
100 gt1 = 2 ! count(1) 100 gt1 = 2 ! count(1)
101 continue ! count(2) 101 continue ! count(2)
end end
...@@ -136,9 +134,7 @@ C Test simple GOTO again, this time out of a DO loop. ...@@ -136,9 +134,7 @@ C Test simple GOTO again, this time out of a DO loop.
if (i .eq. f) goto 100 ! count(19) if (i .eq. f) goto 100 ! count(19)
end do end do
gt2 = 4 ! count(1) gt2 = 4 ! count(1)
! branch(100)
goto 101 ! count(1) goto 101 ! count(1)
! branch(end)
100 gt2 = 8 ! count(1) 100 gt2 = 8 ! count(1)
101 continue ! count(2) 101 continue ! count(2)
end end
...@@ -149,17 +145,13 @@ C Test computed GOTO. ...@@ -149,17 +145,13 @@ C Test computed GOTO.
integer i integer i
goto (101, 102, 103, 104), i ! count(2) goto (101, 102, 103, 104), i ! count(2)
gt3 = 8 ! count(1) gt3 = 8 ! count(1)
! branch(100)
goto 105 ! count(1) goto 105 ! count(1)
! branch(end)
101 gt3 = 1024 101 gt3 = 1024
goto 105 goto 105
102 gt3 = 2048 102 gt3 = 2048
goto 105 goto 105
103 gt3 = 16 ! count(1) 103 gt3 = 16 ! count(1)
! branch(100)
goto 105 ! count(1) goto 105 ! count(1)
! branch(end)
104 gt3 = 4096 104 gt3 = 4096
goto 105 goto 105
105 gt3 = gt3 * 2 ! count(2) 105 gt3 = gt3 * 2 ! count(2)
......
...@@ -168,7 +168,7 @@ proc verify-calls { testcase file } { ...@@ -168,7 +168,7 @@ proc verify-calls { testcase file } {
set n 0 set n 0
while { [gets $fd line] >= 0 } { while { [gets $fd line] >= 0 } {
regexp "^\[^:\]+: *(\[0-9\]+):" "$line" all n regexp "^\[^:\]+: *(\[0-9\]+):" "$line" all n
if [regexp "returns" $line] { if [regexp "return" $line] {
verbose "Processing returns line $n: $line" 3 verbose "Processing returns line $n: $line" 3
if [regexp "returns\\((\[0-9 \]+)\\)" "$line" all new_shouldbe] { if [regexp "returns\\((\[0-9 \]+)\\)" "$line" all new_shouldbe] {
# All percentages in the current list should have been seen. # All percentages in the current list should have been seen.
...@@ -179,12 +179,12 @@ proc verify-calls { testcase file } { ...@@ -179,12 +179,12 @@ proc verify-calls { testcase file } {
} }
# Record the percentages to check for. # Record the percentages to check for.
set shouldbe $new_shouldbe set shouldbe $new_shouldbe
} elseif [regexp "call +\[0-9\]+ returns (-\[0-9\]+)%" "$line" \ } elseif [regexp "call +\[0-9\]+ returned (-\[0-9\]+)%" "$line" \
all returns] { all returns] {
# Percentages should never be negative. # Percentages should never be negative.
fail "$n: negative percentage: $returns" fail "$n: negative percentage: $returns"
incr failed incr failed
} elseif [regexp "call +\[0-9\]+ returns (\[0-9\]+)%" "$line" \ } elseif [regexp "call +\[0-9\]+ returned (\[0-9\]+)%" "$line" \
all returns] { all returns] {
# For branches we check that percentages are not greater than # For branches we check that percentages are not greater than
# 100 but call return percentages can be, as for setjmp(), so # 100 but call return percentages can be, as for setjmp(), so
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment