This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [GCOV] Add all blocks mode, and function summaries


Mark Mitchell wrote:
Yes.  From a docs perspective, it might be a good idea to figure out
what is happening with the line 13 thing; if there were a footnote that
said "this is two basic blocks because the compiler is doing X" that
might help.  Probably not critical, though.
I decided that this is a better fix. Those two bbs are caused by the way
we instrument calls. I've added smarts into gcov to detect this and not
show the pseudo block. I've also added a -u option, because unconditional
branches are not normally interesting - their presence is an accident
of layout, not the shape of the graph itself.

built & tested on i686-pc-linux-gnu.

nathan

--
Nathan Sidwell    ::   http://www.codesourcery.com   ::     CodeSourcery LLC
         The voices in my head said this was stupid too
nathan at codesourcery dot com : http://www.cs.bris.ac.uk/~nathan/ : nathan at acm dot org

2003-03-31  Nathan Sidwell  <nathan at codesourcery dot 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.

Index: gcov-io.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gcov-io.h,v
retrieving revision 1.21
diff -c -3 -p -r1.21 gcov-io.h
*** gcov-io.h	4 Mar 2003 20:56:21 -0000	1.21
--- gcov-io.h	31 Mar 2003 14:43:31 -0000
*************** Software Foundation, 59 Temple Place - S
*** 90,95 ****
--- 90,96 ----
     	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
*************** Software Foundation, 59 Temple Place - S
*** 121,127 ****
  	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 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
--- 122,129 ----
  	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,
!    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
Index: gcov.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gcov.c,v
retrieving revision 1.53
diff -c -3 -p -r1.53 gcov.c
*** gcov.c	18 Jan 2003 22:32:06 -0000	1.53
--- gcov.c	31 Mar 2003 14:43:34 -0000
*************** typedef HOST_WIDEST_INT gcov_type;
*** 69,74 ****
--- 69,75 ----
  
  struct function_info;
  struct block_info;
+ struct source_info;
  
  /* Describes an arc between two basic blocks.  */
  
*************** typedef struct arc_info
*** 86,93 ****
    unsigned int fake : 1;
    unsigned int fall_through : 1;
  
!   /* Arc to a call.  */
!   unsigned int is_call : 1;
    
    /* Next branch on line.  */
    struct arc_info *line_next;
--- 87,103 ----
    unsigned int fake : 1;
    unsigned int fall_through : 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;
*************** typedef struct block_info
*** 112,128 ****
  
    /* Block execution count.  */
    gcov_type count;
    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;
  
!   /* Temporary chain for solving graph.  */
    struct block_info *chain;
    
  } block_t;
--- 122,160 ----
  
    /* Block execution count.  */
    gcov_type count;
+   unsigned flags : 13;
    unsigned count_valid : 1;
    unsigned valid_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
!         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;
*************** typedef struct function_info
*** 138,147 ****
--- 170,187 ----
    /* 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;
*************** typedef struct coverage_info
*** 170,177 ****
  typedef struct line_info
  {
    gcov_type count;	   /* execution count */
!   arc_t *branches; 	   /* branches from blocks that end on this
! 			      line.  */
    unsigned exists : 1;
  } line_t;
  
--- 210,223 ----
  typedef struct line_info
  {
    gcov_type count;	   /* execution count */
!   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;
  
*************** typedef struct source_info
*** 189,194 ****
--- 235,244 ----
    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;
*************** static function_t *functions;
*** 202,207 ****
--- 252,262 ----
  
  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;
*************** static char *da_file_name;
*** 218,223 ****
--- 273,281 ----
  
  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.  */
  
*************** static int flag_gcov_file = 1;
*** 229,234 ****
--- 287,297 ----
  
  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;
*************** static void print_usage PARAMS ((int)) A
*** 256,269 ****
  static void print_version PARAMS ((void)) ATTRIBUTE_NORETURN;
  static void process_file PARAMS ((const char *));
  static void create_file_names PARAMS ((const 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 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 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));
--- 319,334 ----
  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 *, 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));
*************** print_usage (error_p)
*** 328,333 ****
--- 393,399 ----
    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");
*************** print_usage (error_p)
*** 337,342 ****
--- 403,409 ----
    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);
*************** static const struct option options[] =
*** 365,370 ****
--- 432,438 ----
  {
    { "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' },
*************** static const struct option options[] =
*** 373,378 ****
--- 441,447 ----
    { "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.  */
*************** process_args (argc, argv)
*** 384,413 ****
  {
    int opt;
  
!   while ((opt = getopt_long (argc, argv, "hvbclnfo:p", options, NULL)) != -1)
      {
        switch (opt)
  	{
! 	case 'h':
! 	  print_usage (false);
! 	  /* print_usage will exit.  */
! 	case 'v':
! 	  print_version ();
! 	  /* print_version will exit.  */
  	case 'b':
  	  flag_branches = 1;
  	  break;
  	case 'c':
  	  flag_counts = 1;
  	  break;
! 	case 'n':
! 	  flag_gcov_file = 0;
  	  break;
  	case 'l':
  	  flag_long_names = 1;
  	  break;
! 	case 'f':
! 	  flag_function_summary = 1;
  	  break;
  	case 'o':
  	  object_directory = optarg;
--- 453,482 ----
  {
    int opt;
  
!   while ((opt = getopt_long (argc, argv, "abcfhlno:puv", options, NULL)) != -1)
      {
        switch (opt)
  	{
! 	case 'a':
! 	  flag_all_blocks = 1;
! 	  break;
  	case 'b':
  	  flag_branches = 1;
  	  break;
  	case 'c':
  	  flag_counts = 1;
  	  break;
! 	case 'f':
! 	  flag_function_summary = 1;
  	  break;
+ 	case 'h':
+ 	  print_usage (false);
+ 	  /* print_usage will exit.  */
  	case 'l':
  	  flag_long_names = 1;
  	  break;
! 	case 'n':
! 	  flag_gcov_file = 0;
  	  break;
  	case 'o':
  	  object_directory = optarg;
*************** process_args (argc, argv)
*** 415,420 ****
--- 484,495 ----
  	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.  */
*************** release_structures ()
*** 528,534 ****
  	      arc_n = arc->succ_next;
  	      free (arc);
  	    }
- 	  free (block->encoding);
  	}
        free (fn->blocks);
        free (fn->counts);
--- 603,608 ----
*************** create_file_names (file_name)
*** 597,602 ****
--- 671,704 ----
    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
*************** read_graph_file ()
*** 650,671 ****
  	goto corrupt;
  
        base = gcov_save_position (file);
!       
        if (tag == GCOV_TAG_FUNCTION)
  	{
  	  char *function_name = NULL;
! 	  unsigned checksum;
  
  	  if (gcov_read_string (file, &function_name, NULL)
! 	      || gcov_read_unsigned (file, &checksum))
  	    goto corrupt;
  	  fn = (function_t *)xcalloc (1, sizeof (function_t));
  	  fn->name = function_name;
  	  fn->checksum = checksum;
  
  	  fn->next = functions;
  	  functions = fn;
  	  current_tag = tag;
  	}
        else if (fn && tag == GCOV_TAG_BLOCKS)
  	{
--- 752,796 ----
  	goto corrupt;
  
        base = gcov_save_position (file);
! 
        if (tag == GCOV_TAG_FUNCTION)
  	{
  	  char *function_name = NULL;
! 	  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_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)
  	{
*************** read_graph_file ()
*** 674,682 ****
  		     bbg_file_name, fn->name);
  	  else
  	    {
! 	      fn->num_blocks = length / 4;
  	      fn->blocks
  		= (block_t *)xcalloc (fn->num_blocks, sizeof (block_t));
  	    }
  	}
        else if (fn && tag == GCOV_TAG_ARCS)
--- 799,817 ----
  		     bbg_file_name, fn->name);
  	  else
  	    {
! 	      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)
*************** read_graph_file ()
*** 717,723 ****
  	      fn->blocks[dest].pred = arc;
  	      fn->blocks[dest].num_pred++;
  
! 	      arc->is_call = arc->fake;
  	      
  	      if (!arc->on_tree)
  		fn->num_counts++;
--- 852,875 ----
  	      fn->blocks[dest].pred = arc;
  	      fn->blocks[dest].num_pred++;
  
! 	      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++;
*************** read_graph_file ()
*** 731,737 ****
  
  	  if (gcov_read_unsigned (file, &blockno)
  	      || blockno >= fn->num_blocks
! 	      || fn->blocks[blockno].encoding)
  	    goto corrupt;
  	  
  	  for (ix = 0; ;  )
--- 883,889 ----
  
  	  if (gcov_read_unsigned (file, &blockno)
  	      || blockno >= fn->num_blocks
! 	      || fn->blocks[blockno].u.line.encoding)
  	    goto corrupt;
  	  
  	  for (ix = 0; ;  )
*************** read_graph_file ()
*** 759,786 ****
  		    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;
! 		    }
  		  line_nos[ix++] = 0;
  		  line_nos[ix++] = src->index;
  		}
  	    }
  	  
! 	  fn->blocks[blockno].encoding = line_nos;
! 	  fn->blocks[blockno].num_encodings = ix;
  	}
        else if (current_tag && !GCOV_TAG_IS_SUBTAG (current_tag, tag))
  	{
--- 911,925 ----
  		    goto corrupt;
  		  if (!file_name)
  		    break;
! 		  src = find_source (file_name);
! 		  
  		  line_nos[ix++] = 0;
  		  line_nos[ix++] = src->index;
  		}
  	    }
  	  
! 	  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))
  	{
*************** read_count_file ()
*** 906,912 ****
  	  goto cleanup;
  	}
        base = gcov_save_position (file);
!       if (tag == GCOV_TAG_FUNCTION)
  	{
  	  unsigned checksum;
  	  struct function_info *fn_n = functions;
--- 1045,1059 ----
  	  goto cleanup;
  	}
        base = gcov_save_position (file);
!       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;
*************** solve_flow_graph (fn)
*** 977,982 ****
--- 1124,1130 ----
    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.  */
    
*************** solve_flow_graph (fn)
*** 1004,1028 ****
  
    /* 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++)
      {
        block_t const *prev_dst = NULL;
        int out_of_order = 0;
        
!       for (arc = fn->blocks[ix].succ; arc; arc = arc->succ_next)
  	{
  	  if (!arc->on_tree)
  	    {
  	      if (count_ptr)
  		arc->count = *count_ptr++;
  	      arc->count_valid = 1;
! 	      fn->blocks[ix].num_succ--;
  	      arc->dst->num_pred--;
  	    }
  	  if (prev_dst && prev_dst > arc->dst)
  	    out_of_order = 1;
  	  prev_dst = arc->dst;
  	}
        
        /* Sort the successor arcs into ascending dst order. profile.c
  	 normally produces arcs in the right order, but sometimes with
--- 1152,1201 ----
  
    /* Propagate the measured counts, this must be done in the same
       order as the code in profile.c  */
!   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 = 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;
! 	      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
*************** solve_flow_graph (fn)
*** 1030,1036 ****
  	 smart sort.  */
        if (out_of_order)
  	{
! 	  arc_t *start = fn->blocks[ix].succ;
  	  unsigned changes = 1;
  	  
  	  while (changes)
--- 1203,1209 ----
  	 smart sort.  */
        if (out_of_order)
  	{
! 	  arc_t *start = blk->succ;
  	  unsigned changes = 1;
  	  
  	  while (changes)
*************** solve_flow_graph (fn)
*** 1058,1077 ****
  		    }
  		}
  	    }
! 	  fn->blocks[ix].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];
      }
  
    while (invalid_blocks || valid_blocks)
      {
-       block_t *blk;
-       
        while ((blk = invalid_blocks))
  	{
  	  gcov_type total = 0;
--- 1231,1248 ----
  		    }
  		}
  	    }
! 	  blk->succ = start;
  	}
        
        /* Place it on the invalid chain, it will be ignored if that's
  	 wrong.  */
!       blk->invalid_chain = 1;
!       blk->chain = invalid_blocks;
!       invalid_blocks = blk;
      }
  
    while (invalid_blocks || valid_blocks)
      {
        while ((blk = invalid_blocks))
  	{
  	  gcov_type total = 0;
*************** add_branch_counts (coverage, arc)
*** 1196,1208 ****
       coverage_t *coverage;
       const arc_t *arc;
  {
!   if (arc->is_call)
      {
        coverage->calls++;
        if (arc->src->count)
  	coverage->calls_executed++;
      }
!   else
      {
        coverage->branches++;
        if (arc->src->count)
--- 1367,1379 ----
       coverage_t *coverage;
       const arc_t *arc;
  {
!   if (arc->is_call_non_return)
      {
        coverage->calls++;
        if (arc->src->count)
  	coverage->calls_executed++;
      }
!   else if (!arc->is_unconditional)
      {
        coverage->branches++;
        if (arc->src->count)
*************** make_gcov_file_name (input_name, src_nam
*** 1374,1380 ****
  static void
  add_line_counts (coverage, fn)
       coverage_t *coverage;
!      const function_t *fn;
  {
    unsigned ix;
    line_t *line = NULL; /* this is propagated from one iteration to the
--- 1545,1551 ----
  static void
  add_line_counts (coverage, fn)
       coverage_t *coverage;
!      function_t *fn;
  {
    unsigned ix;
    line_t *line = NULL; /* this is propagated from one iteration to the
*************** add_line_counts (coverage, fn)
*** 1383,1395 ****
    /* Scan each basic block.  */
    for (ix = 0; ix != fn->num_blocks; ix++)
      {
!       const block_t *block = &fn->blocks[ix];
        unsigned *encoding;
        const source_t *src = NULL;
        unsigned jx;
  
!       for (jx = 0, encoding = block->encoding;
! 	   jx != block->num_encodings; jx++, encoding++)
  	if (!*encoding)
  	  {
  	    unsigned src_n = *++encoding;
--- 1554,1569 ----
    /* Scan each basic block.  */
    for (ix = 0; ix != fn->num_blocks; ix++)
      {
!       block_t *block = &fn->blocks[ix];
        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++;
!       for (jx = 0, encoding = block->u.line.encoding;
! 	   jx != block->u.line.num; jx++, encoding++)
  	if (!*encoding)
  	  {
  	    unsigned src_n = *++encoding;
*************** add_line_counts (coverage, fn)
*** 1406,1431 ****
  	      {
  		if (!line->exists)
  		  coverage->lines++;
! 		if  (!line->count && block->count)
  		  coverage->lines_executed++;
  	      }
  	    line->exists = 1;
  	    line->count += block->count;
  	  }
!       
!       if (line && 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)
  		add_branch_counts (coverage, arc);
  	    }
  	}
--- 1580,1617 ----
  	      {
  		if (!line->exists)
  		  coverage->lines++;
! 		if (!line->count && block->count)
  		  coverage->lines_executed++;
  	      }
  	    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;
! 	  
!       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)
  	    {
! 	      arc->line_next = line->u.branches;
! 	      line->u.branches = arc;
! 	      if (coverage && !arc->is_unconditional)
  		add_branch_counts (coverage, arc);
  	    }
  	}
*************** accumulate_line_counts (src)
*** 1441,1462 ****
       source_t *src;
  {
    line_t *line;
    unsigned ix;
    
    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)
  	{
! 	  arc_n = arc->line_next;
! 	  arc->line_next = arc_p;
! 
! 	  add_branch_counts (&src->coverage, arc);
  	}
!       line->branches = arc_p;
  
        if (line->exists)
  	{
  	  src->coverage.lines++;
--- 1627,1749 ----
       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++)
      {
!       if (!flag_all_blocks)
  	{
! 	  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;
  	}
!       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++;
*************** accumulate_line_counts (src)
*** 1466,1471 ****
--- 1753,1802 ----
      }
  }
  
+ /* 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.  */
*************** output_lines (gcov_file, src)
*** 1480,1489 ****
--- 1811,1823 ----
    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)
*************** output_lines (gcov_file, src)
*** 1508,1513 ****
--- 1842,1866 ----
    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,
*************** output_lines (gcov_file, src)
*** 1535,1570 ****
  	}
        if (!retval)
  	fputs ("??\n", gcov_file);
!       
!       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);
! 		}
  	    }
  	}
      }
    
--- 1888,1920 ----
  	}
        if (!retval)
  	fputs ("??\n", gcov_file);
! 
!       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->u.branches; arc; arc = arc->line_next)
+ 	    ix += output_branch_count (gcov_file, ix, arc);
  	}
      }
    
Index: profile.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/profile.c,v
retrieving revision 1.109
diff -c -3 -p -r1.109 profile.c
*** profile.c	30 Mar 2003 22:01:00 -0000	1.109
--- profile.c	31 Mar 2003 14:43:39 -0000
*************** branch_prob ()
*** 926,932 ****
    unsigned num_edges, ignored_edges;
    struct edge_list *el;
    const char *name = IDENTIFIER_POINTER
! 		      (DECL_ASSEMBLER_NAME (current_function_decl));
  
    profile_info.current_function_cfg_checksum = compute_checksum ();
    for (i = 0; i < profile_info.n_sections; i++)
--- 926,932 ----
    unsigned num_edges, ignored_edges;
    struct edge_list *el;
    const char *name = IDENTIFIER_POINTER
!     (DECL_ASSEMBLER_NAME (current_function_decl));
  
    profile_info.current_function_cfg_checksum = compute_checksum ();
    for (i = 0; i < profile_info.n_sections; i++)
*************** branch_prob ()
*** 1086,1091 ****
--- 1086,1093 ----
    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)
*************** branch_prob ()
*** 1094,1099 ****
--- 1096,1103 ----
  			     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;
  
Index: doc/gcov.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/gcov.texi,v
retrieving revision 1.14
diff -c -3 -p -r1.14 gcov.texi
*** doc/gcov.texi	4 Feb 2003 01:27:46 -0000	1.14
--- doc/gcov.texi	31 Mar 2003 14:43:48 -0000
*************** gcov @r{[} at var{options}@r{]} @var{source
*** 120,125 ****
--- 120,126 ----
  @ignore
  @c man begin SYNOPSIS
  gcov [ at option{-v}|@option{--version}] [ at option{-h}|@option{--help}]
+      [ at option{-a}|@option{--all-blocks}]
       [ at option{-b}|@option{--branch-probabilities}]
       [ at option{-c}|@option{--branch-counts}]
       [ at option{-n}|@option{--no-output}]
*************** gcov [ at option{-v}|@option{--version}] [@
*** 127,132 ****
--- 128,134 ----
       [ at option{-p}|@option{--preserve-paths}]
       [ at option{-f}|@option{--function-summaries}]
       [ at option{-o}|@option{--object-directory} @var{directory|file}] @var{sourcefile}
+      [ at 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}.
*************** exit without doing any further processin
*** 145,155 ****
  Display the @command{gcov} version number (on the standard output),
  and exit without doing any further processing.
  
  @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.
  
  @item -c
  @itemx --branch-counts
--- 147,169 ----
  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. Unconditional branches will not
! be shown, unless the @option{-u} option is given.
  
  @item -c
  @itemx --branch-counts
*************** source file name, without its extension.
*** 192,197 ****
--- 206,216 ----
  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
*************** Here is a sample:
*** 248,273 ****
  
  @smallexample
          -:    0:Source:tmp.c
!         -:    0:Object:tmp.bb
          -:    1:#include <stdio.h>
          -:    2:
          -:    3:int main (void)
          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;
!         1:   17:@}
  @end smallexample
  
  @need 450
  When you use the @option{-b} option, your output looks like this:
  
--- 267,334 ----
  
  @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:    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>
          -:    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:
  
*************** Here is a sample of a resulting @file{tm
*** 284,314 ****
  
  @smallexample
          -:    0:Source:tmp.c
!         -:    0:Object:tmp.bb
          -:    1:#include <stdio.h>
          -:    2:
          -:    3:int main (void)
          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%
         10:   10:    total += i;
          -:   11:  
          1:   12:  if (total != 45)
! branch  0: taken 100%
      #####:   13:    printf ("Failure\n");
! call    0: never executed
! branch  1: never executed
          -:   14:  else
          1:   15:    printf ("Success\n");
! call    0: returns 100%
          1:   16:  return 0;
!         1:   17:@}
  @end smallexample
  
  For each basic block, a line is printed after the last line of the basic
--- 345,378 ----
  
  @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:    5:  int i, total;
          -:    6:  
          1:    7:  total = 0;
          -:    8:  
         11:    9:  for (i = 0; i < 10; i++)
! branch  0 taken 91% (fallthrough)
! branch  1 taken 9%
         10:   10:    total += i;
          -:   11:  
          1:   12:  if (total != 45)
! branch  0 taken 0% (fallthrough)
! branch  1 taken 100%
      #####:   13:    printf ("Failure\n");
! call    0 never executed
          -:   14:  else
          1:   15:    printf ("Success\n");
! call    0 called 1 returned 100%
          1:   16:  return 0;
!         -:   17:@}
  @end smallexample
  
  For each basic block, a line is printed after the last line of the basic
Index: testsuite/g77.dg/gcov/gcov-1.f
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g77.dg/gcov/gcov-1.f,v
retrieving revision 1.2
diff -c -3 -p -r1.2 gcov-1.f
*** testsuite/g77.dg/gcov/gcov-1.f	27 Mar 2003 23:53:08 -0000	1.2
--- testsuite/g77.dg/gcov/gcov-1.f	31 Mar 2003 14:44:10 -0000
*************** C Test simple GOTO.
*** 118,126 ****
        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
--- 118,124 ----
*************** C Test simple GOTO again, this time out 
*** 136,144 ****
           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
--- 134,140 ----
*************** C Test computed GOTO.
*** 149,165 ****
        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)
--- 145,157 ----
Index: testsuite/lib/gcov.exp
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/lib/gcov.exp,v
retrieving revision 1.3
diff -c -3 -p -r1.3 gcov.exp
*** testsuite/lib/gcov.exp	27 Mar 2003 23:53:08 -0000	1.3
--- testsuite/lib/gcov.exp	31 Mar 2003 14:44:20 -0000
*************** proc verify-calls { testcase file } {
*** 168,174 ****
      set n 0
      while { [gets $fd line] >= 0 } {
  	regexp "^\[^:\]+: *(\[0-9\]+):" "$line" all n
! 	if [regexp "returns" $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.
--- 168,174 ----
      set n 0
      while { [gets $fd line] >= 0 } {
  	regexp "^\[^:\]+: *(\[0-9\]+):" "$line" all n
! 	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.
*************** proc verify-calls { testcase file } {
*** 179,190 ****
  		}
  	        # Record the percentages to check for.
  		set shouldbe $new_shouldbe
! 	    } elseif [regexp "call +\[0-9\]+ returns (-\[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" \
  			all returns] {
  		# For branches we check that percentages are not greater than
  		# 100 but call return percentages can be, as for setjmp(), so
--- 179,190 ----
  		}
  	        # Record the percentages to check for.
  		set shouldbe $new_shouldbe
! 	    } 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\]+ 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

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]