Please review the new patch which only implements cfg checksum.

The auto version generation was introduced in 2002 before FDO support
was added (so the old way never existed), so it might be better to
make the change independent of this one.

Thanks,

David

On Thu, Apr 21, 2011 at 2:15 PM, Xinliang David Li <davi...@google.com> wrote:
> On Thu, Apr 21, 2011 at 1:43 PM, Jan Hubicka <hubi...@ucw.cz> wrote:
>>> > I don't really follow the logic here.  buffer is allocated to be size of
>>> > block+4 and it is expected that gcov_write_words is not executed on size
>>> > greater than 4.  Since gcov_write_string now seems to be expected to 
>>> > handle
>>> > strings of bigger size, I think you acually need to make write_string to 
>>> > write
>>> > in chunks when you reach block boundary?
>>>
>>> gcov_write_words is used to reserve words*4 bytes in buffer for data
>>> write later. The the old logic is wrong -- if 'words' is large enough,
>>> it will lead to out of bound access.
>>
>> The old logic assumes that writes are not bigger than 4 and it is documented
>> somewhere in gcov-io.h if I remember right (it is not my code).
>> I however still think your change won't solve it in general, since you might
>> want to write more than block size, so you need write_string update.
>
> Right, 'words; can be large for string. -- the memcpy code following
> does not look right either.
>
>
>>> >
>>> > What gets into libgcov is very problematic busyness for embedded targets, 
>>> > where you really want
>>> > libgcov to be small.  Why do you need to store strings now?
>>>
>>> It is needed to store the assembler name for functions. It allows
>>> lookup of the profile data using assembler name as key instead of
>>> using function ids. For gcc, the total size of gcda files is about 59k
>>> bytes without storing the names, and about 65k with names -- about 10%
>>> increase. For eon, the size changes from 27k to 35k bytes.
>>>
>>> I can split the patches into two parts -- one with cfg checksum and
>>> one with the name string.
>>
>> Well, lets make it incremental change then at time we will have use for it 
>> once
>> we agree it makes sense.
>
> Ok.
>
>>  So you want to do symbol name resolving at GCOV
>> runtime?
>
> For now, it is just passed through as a tag for the profile data for
> each function.
>
>> I duno about embedded targets, 10% increase is not too bad, but I don't know.
>> libgcov has quite inflexible coding style just to be small and fit there, so
>> I don't know what are the space constraints that are considered acceptable
>> in that world.
>
> I will delay the string writing patch for now.
>
>>> > We also need to bump gcov version, right?
>>>
>>> Yes -- but the version is currently derived from gcc version number
>>> and phase number --- this is wrong -- different version of gcc may
>>> have compatible coverage data format.  Any suggestions to change this?
>>> --- probably just hard code the GCOV_VERSION string?
>>
>> Hmm, I am pretty sure we used to have minor/major numbering on the file 
>> format.
>> Perhaps it went away with Nathan's changes.  For -fprofile-use the 
>> compatibility
>> across versions is pointless,
>
> Right, but also equally unnecessary to force version mismatch between
> compiler releases.
>
>>at least now, but for gcov utility it makes sense.
>
> Yes.
>
>> So I would go for explicit versioning again.
>>
>
> Will dig through the revision history ..
>
> David
>
>> Honza
>>
>
Index: tree.c
===================================================================
--- tree.c	(revision 172802)
+++ tree.c	(working copy)
@@ -8513,14 +8513,12 @@ dump_tree_statistics (void)
 
 #define FILE_FUNCTION_FORMAT "_GLOBAL__%s_%s"
 
-/* Generate a crc32 of a string.  */
+/* Generate a crc32 of a byte.  */
 
 unsigned
-crc32_string (unsigned chksum, const char *string)
+crc32_byte (unsigned chksum, char byte)
 {
-  do
-    {
-      unsigned value = *string << 24;
+  unsigned value = (unsigned) byte << 24;
       unsigned ix;
 
       for (ix = 8; ix--; value <<= 1)
@@ -8531,6 +8529,18 @@ crc32_string (unsigned chksum, const cha
  	  chksum <<= 1;
  	  chksum ^= feedback;
   	}
+  return chksum;
+}
+
+
+/* Generate a crc32 of a string.  */
+
+unsigned
+crc32_string (unsigned chksum, const char *string)
+{
+  do
+    {
+      chksum = crc32_byte (chksum, *string);
     }
   while (*string++);
   return chksum;
@@ -8554,8 +8564,10 @@ clean_symbol_name (char *p)
       *p = '_';
 }
 
-/* Generate a name for a special-purpose function function.
+/* Generate a name for a special-purpose function.
    The generated name may need to be unique across the whole link.
+   Changes to this function may also require corresponding changes to
+   xstrdup_mask_random.
    TYPE is some string to identify the purpose of this function to the
    linker or collect2; it must start with an uppercase letter,
    one of:
Index: tree.h
===================================================================
--- tree.h	(revision 172802)
+++ tree.h	(working copy)
@@ -4998,6 +4998,7 @@ inlined_function_outer_scope_p (const_tr
 
 /* In tree.c */
 extern unsigned crc32_string (unsigned, const char *);
+extern unsigned crc32_byte (unsigned, char);
 extern void clean_symbol_name (char *);
 extern tree get_file_function_name (const char *);
 extern tree get_callee_fndecl (const_tree);
Index: gcov.c
===================================================================
--- gcov.c	(revision 172802)
+++ gcov.c	(working copy)
@@ -54,6 +54,13 @@ along with Gcov; see the file COPYING3. 
    some places we make use of the knowledge of how profile.c works to
    select particular algorithms here.  */
 
+/* The code validates that the profile information read in corresponds
+   to the code currently being compiled.  Rather than checking for
+   identical files, the code below computes a checksum on the CFG
+   (based on the order of basic blocks and the arcs in the CFG).  If
+   the CFG checksum in the gcda file match the CFG checksum for the
+   code currently being compiled, the profile data will be used.  */
+
 /* This is the size of the buffer used to read in source file lines.  */
 
 #define STRING_SIZE 200
@@ -161,7 +168,8 @@ typedef struct function_info
   /* Name of function.  */
   char *name;
   unsigned ident;
-  unsigned checksum;
+  unsigned lineno_checksum;
+  unsigned cfg_checksum;
 
   /* Array of basic blocks.  */
   block_t *blocks;
@@ -807,12 +815,14 @@ read_graph_file (void)
       if (tag == GCOV_TAG_FUNCTION)
 	{
 	  char *function_name;
-	  unsigned ident, checksum, lineno;
+	  unsigned ident, lineno;
+	  unsigned lineno_checksum, cfg_checksum;
 	  source_t *src;
 	  function_t *probe, *prev;
 
 	  ident = gcov_read_unsigned ();
-	  checksum = gcov_read_unsigned ();
+	  lineno_checksum = gcov_read_unsigned ();
+	  cfg_checksum = gcov_read_unsigned ();
 	  function_name = xstrdup (gcov_read_string ());
 	  src = find_source (gcov_read_string ());
 	  lineno = gcov_read_unsigned ();
@@ -820,7 +830,8 @@ read_graph_file (void)
 	  fn = XCNEW (function_t);
 	  fn->name = function_name;
 	  fn->ident = ident;
-	  fn->checksum = checksum;
+	  fn->lineno_checksum = lineno_checksum;
+	  fn->cfg_checksum = cfg_checksum;
 	  fn->src = src;
 	  fn->line = lineno;
 
@@ -1107,7 +1118,8 @@ read_count_file (void)
 
 	  if (!fn)
 	    ;
-	  else if (gcov_read_unsigned () != fn->checksum)
+	  else if (gcov_read_unsigned () != fn->lineno_checksum
+		   || gcov_read_unsigned () != fn->cfg_checksum)
 	    {
 	    mismatch:;
 	      fnotice (stderr, "%s:profile mismatch for '%s'\n",
Index: testsuite/gcc.dg/tree-prof/prof-robust-1.c
===================================================================
--- testsuite/gcc.dg/tree-prof/prof-robust-1.c	(revision 0)
+++ testsuite/gcc.dg/tree-prof/prof-robust-1.c	(revision 0)
@@ -0,0 +1,25 @@
+/* { dg-options "-O2 -w" } */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef _PROFILE_USE
+int foo(int x) {
+  return 3 * x;
+}
+#else
+int foo(int x) {
+  return 3 * x;
+}
+#endif
+
+int x = 1000;
+
+int main(int argc, char *argv[]) {
+  int i;
+  int sum = 0;
+  for (i = 0; i < x; i++)
+    sum += i;
+  printf("%d\n", sum);
+  return 0;
+}
Index: testsuite/g++.dg/prof-robust-1.C
===================================================================
--- testsuite/g++.dg/prof-robust-1.C	(revision 0)
+++ testsuite/g++.dg/prof-robust-1.C	(revision 0)
@@ -0,0 +1,24 @@
+/* { dg-options "-O2 -fno-weak" } */
+
+#include <stdio.h>
+
+namespace {
+  namespace {
+    
+    class MyClass {
+    public:
+      void foo() const;
+      ~MyClass() { foo(); }
+    };
+    
+    void MyClass::foo() const { printf("Goodbye World\n"); }
+    
+  }
+  
+  static MyClass variable;
+  
+}
+
+int main() {
+  return 0;
+}
Index: gcov-io.h
===================================================================
--- gcov-io.h	(revision 172802)
+++ gcov-io.h	(working copy)
@@ -103,7 +103,8 @@ see the files COPYING3 and COPYING.RUNTI
    	note: unit function-graph*
 	unit: header int32:checksum string:source
 	function-graph: announce_function basic_blocks {arcs | lines}*
-	announce_function: header int32:ident int32:checksum
+	announce_function: header int32:ident
+		int32:lineno_checksum int32:cfg_checksum
 		string:name string:source int32:lineno
 	basic_block: header int32:flags*
 	arcs: header int32:block_no arc*
@@ -132,7 +133,8 @@ see the files COPYING3 and COPYING.RUNTI
         data: {unit function-data* summary:object summary:program*}*
 	unit: header int32:checksum
         function-data:	announce_function arc_counts
-	announce_function: header int32:ident int32:checksum
+	announce_function: header int32:ident
+		int32:lineno_checksum int32:cfg_checksum
 	arc_counts: header int64:count*
 	summary: int32:checksum {count-summary}GCOV_COUNTERS
 	count-summary:	int32:num int32:runs int64:sum
@@ -294,7 +296,7 @@ typedef HOST_WIDEST_INT gcov_type;
    file marker -- it is not required to be present.  */
 
 #define GCOV_TAG_FUNCTION	 ((gcov_unsigned_t)0x01000000)
-#define GCOV_TAG_FUNCTION_LENGTH (2)
+#define GCOV_TAG_FUNCTION_LENGTH (3)
 #define GCOV_TAG_BLOCKS		 ((gcov_unsigned_t)0x01410000)
 #define GCOV_TAG_BLOCKS_LENGTH(NUM) (NUM)
 #define GCOV_TAG_BLOCKS_NUM(LENGTH) (LENGTH)
@@ -412,10 +414,12 @@ struct gcov_summary
    idiom. The number of counters is determined from the counter_mask
    in gcov_info.  We hold an array of function info, so have to
    explicitly calculate the correct array stride.  */
+
 struct gcov_fn_info
 {
   gcov_unsigned_t ident;	/* unique ident of function */
-  gcov_unsigned_t checksum;	/* function checksum */
+  gcov_unsigned_t lineno_checksum;	/* function lineo_checksum */
+  gcov_unsigned_t cfg_checksum;	/* function cfg checksum */
   unsigned n_ctrs[0];		/* instrumented counters */
 };
 
Index: profile.c
===================================================================
--- profile.c	(revision 172802)
+++ profile.c	(working copy)
@@ -102,13 +102,6 @@ static int total_num_branches;
 
 /* Forward declarations.  */
 static void find_spanning_tree (struct edge_list *);
-static unsigned instrument_edges (struct edge_list *);
-static void instrument_values (histogram_values);
-static void compute_branch_probabilities (void);
-static void compute_value_histograms (histogram_values);
-static gcov_type * get_exec_counts (void);
-static basic_block find_group (basic_block);
-static void union_groups (basic_block, basic_block);
 
 /* Add edge instrumentation code to the entire insn chain.
 
@@ -233,10 +226,12 @@ instrument_values (histogram_values valu
 }
 
 
-/* Computes hybrid profile for all matching entries in da_file.  */
+/* Computes hybrid profile for all matching entries in da_file.  
+   
+   CFG_CHECKSUM is the precomputed checksum for the CFG.  */
 
 static gcov_type *
-get_exec_counts (void)
+get_exec_counts (unsigned cfg_checksum, unsigned lineno_checksum)
 {
   unsigned num_edges = 0;
   basic_block bb;
@@ -253,7 +248,8 @@ get_exec_counts (void)
 	  num_edges++;
     }
 
-  counts = get_coverage_counts (GCOV_COUNTER_ARCS, num_edges, &profile_info);
+  counts = get_coverage_counts (GCOV_COUNTER_ARCS, num_edges, cfg_checksum,
+				lineno_checksum, &profile_info);
   if (!counts)
     return NULL;
 
@@ -442,10 +438,12 @@ read_profile_edge_counts (gcov_type *exe
 }
 
 /* Compute the branch probabilities for the various branches.
-   Annotate them accordingly.  */
+   Annotate them accordingly.  
+
+   CFG_CHECKSUM is the precomputed checksum for the CFG.  */
 
 static void
-compute_branch_probabilities (void)
+compute_branch_probabilities (unsigned cfg_checksum, unsigned lineno_checksum)
 {
   basic_block bb;
   int i;
@@ -454,7 +452,7 @@ compute_branch_probabilities (void)
   int passes;
   int hist_br_prob[20];
   int num_branches;
-  gcov_type *exec_counts = get_exec_counts ();
+  gcov_type *exec_counts = get_exec_counts (cfg_checksum, lineno_checksum);
   int inconsistent = 0;
 
   /* Very simple sanity checks so we catch bugs in our profiling code.  */
@@ -772,10 +770,13 @@ compute_branch_probabilities (void)
 }
 
 /* Load value histograms values whose description is stored in VALUES array
-   from .gcda file.  */
+   from .gcda file.  
+
+   CFG_CHECKSUM is the precomputed checksum for the CFG.  */
 
 static void
-compute_value_histograms (histogram_values values)
+compute_value_histograms (histogram_values values, unsigned cfg_checksum,
+                          unsigned lineno_checksum)
 {
   unsigned i, j, t, any;
   unsigned n_histogram_counters[GCOV_N_VALUE_COUNTERS];
@@ -803,7 +804,8 @@ compute_value_histograms (histogram_valu
 
       histogram_counts[t] =
 	get_coverage_counts (COUNTER_FOR_HIST_TYPE (t),
-			     n_histogram_counters[t], NULL);
+			     n_histogram_counters[t], cfg_checksum,
+			     lineno_checksum, NULL);
       if (histogram_counts[t])
 	any = 1;
       act_count[t] = histogram_counts[t];
@@ -905,6 +907,7 @@ branch_prob (void)
   unsigned num_instrumented;
   struct edge_list *el;
   histogram_values values = NULL;
+  unsigned cfg_checksum, lineno_checksum;
 
   total_num_times_called++;
 
@@ -1058,11 +1061,19 @@ branch_prob (void)
   if (dump_file)
     fprintf (dump_file, "%d ignored edges\n", ignored_edges);
 
+
+  /* Compute two different checksums. Note that we want to compute
+     the checksum in only once place, since it depends on the shape
+     of the control flow which can change during 
+     various transformations.  */
+  cfg_checksum = coverage_compute_cfg_checksum ();
+  lineno_checksum = coverage_compute_lineno_checksum ();
+
   /* Write the data from which gcov can reconstruct the basic block
      graph.  */
 
   /* Basic block flags */
-  if (coverage_begin_output ())
+  if (coverage_begin_output (lineno_checksum, cfg_checksum))
     {
       gcov_position_t offset;
 
@@ -1079,7 +1090,7 @@ branch_prob (void)
   EXIT_BLOCK_PTR->index = last_basic_block;
 
   /* Arcs */
-  if (coverage_begin_output ())
+  if (coverage_begin_output (lineno_checksum, cfg_checksum))
     {
       gcov_position_t offset;
 
@@ -1120,7 +1131,7 @@ branch_prob (void)
     }
 
   /* Line numbers.  */
-  if (coverage_begin_output ())
+  if (coverage_begin_output (lineno_checksum, cfg_checksum))
     {
       /* Initialize the output.  */
       output_location (NULL, 0, NULL, NULL);
@@ -1175,9 +1186,9 @@ branch_prob (void)
 
   if (flag_branch_probabilities)
     {
-      compute_branch_probabilities ();
+      compute_branch_probabilities (cfg_checksum, lineno_checksum);
       if (flag_profile_values)
-	compute_value_histograms (values);
+	compute_value_histograms (values, cfg_checksum, lineno_checksum);
     }
 
   remove_fake_edges ();
@@ -1205,7 +1216,7 @@ branch_prob (void)
 
   VEC_free (histogram_value, heap, values);
   free_edge_list (el);
-  coverage_end_function ();
+  coverage_end_function (lineno_checksum, cfg_checksum);
 }
 
 /* Union find algorithm implementation for the basic blocks using
@@ -1372,4 +1383,3 @@ end_branch_prob (void)
 	}
     }
 }
-
Index: coverage.c
===================================================================
--- coverage.c	(revision 172802)
+++ coverage.c	(working copy)
@@ -51,13 +51,15 @@ along with GCC; see the file COPYING3.  
 #include "intl.h"
 #include "filenames.h"
 
+#include "gcov-io.h"
 #include "gcov-io.c"
 
 struct function_list
 {
   struct function_list *next;	 /* next function */
   unsigned ident;		 /* function ident */
-  unsigned checksum;	         /* function checksum */
+  unsigned lineno_checksum;	 /* function lineno checksum */
+  unsigned cfg_checksum;	 /* function cfg checksum */
   unsigned n_ctrs[GCOV_COUNTERS];/* number of counters.  */
 };
 
@@ -69,7 +71,8 @@ typedef struct counts_entry
   unsigned ctr;
 
   /* Store  */
-  unsigned checksum;
+  unsigned lineno_checksum;
+  unsigned cfg_checksum;
   gcov_type *counts;
   struct gcov_ctr_summary summary;
 
@@ -114,8 +117,6 @@ static hashval_t htab_counts_entry_hash 
 static int htab_counts_entry_eq (const void *, const void *);
 static void htab_counts_entry_del (void *);
 static void read_counts_file (void);
-static unsigned compute_checksum (void);
-static unsigned coverage_checksum_string (unsigned, const char *);
 static tree build_fn_info_type (unsigned);
 static tree build_fn_info_value (const struct function_list *, tree);
 static tree build_ctr_info_type (void);
@@ -171,11 +172,12 @@ static void
 read_counts_file (void)
 {
   gcov_unsigned_t fn_ident = 0;
-  gcov_unsigned_t checksum = -1;
   counts_entry_t *summaried = NULL;
   unsigned seen_summary = 0;
   gcov_unsigned_t tag;
   int is_error = 0;
+  unsigned lineno_checksum = 0;
+  unsigned cfg_checksum = 0;
 
   if (!gcov_open (da_file_name, 1))
     return;
@@ -215,7 +217,8 @@ read_counts_file (void)
       if (tag == GCOV_TAG_FUNCTION)
 	{
 	  fn_ident = gcov_read_unsigned ();
-	  checksum = gcov_read_unsigned ();
+	  lineno_checksum = gcov_read_unsigned ();
+	  cfg_checksum = gcov_read_unsigned ();
 	  if (seen_summary)
 	    {
 	      /* We have already seen a summary, this means that this
@@ -265,17 +268,21 @@ read_counts_file (void)
 	  if (!entry)
 	    {
 	      *slot = entry = XCNEW (counts_entry_t);
-	      entry->ident = elt.ident;
+	      entry->ident = fn_ident;
 	      entry->ctr = elt.ctr;
-	      entry->checksum = checksum;
+	      entry->lineno_checksum = lineno_checksum;
+	      entry->cfg_checksum = cfg_checksum;
 	      entry->summary.num = n_counts;
 	      entry->counts = XCNEWVEC (gcov_type, n_counts);
 	    }
-	  else if (entry->checksum != checksum)
+	  else if (entry->lineno_checksum != lineno_checksum
+		   || entry->cfg_checksum != cfg_checksum)
 	    {
 	      error ("coverage mismatch for function %u while reading execution counters",
 		     fn_ident);
-	      error ("checksum is %x instead of %x", entry->checksum, checksum);
+	      error ("checksum is (%x,%x) instead of (%x,%x)",
+		     entry->lineno_checksum, entry->cfg_checksum,
+		     lineno_checksum, cfg_checksum);
 	      htab_delete (counts_hash);
 	      break;
 	    }
@@ -324,10 +331,10 @@ read_counts_file (void)
 
 gcov_type *
 get_coverage_counts (unsigned counter, unsigned expected,
+                     unsigned cfg_checksum, unsigned lineno_checksum,
 		     const struct gcov_ctr_summary **summary)
 {
   counts_entry_t *entry, elt;
-  gcov_unsigned_t checksum = -1;
 
   /* No hash table, no counts.  */
   if (!counts_hash)
@@ -352,23 +359,22 @@ get_coverage_counts (unsigned counter, u
       return NULL;
     }
 
-  checksum = compute_checksum ();
-  if (entry->checksum != checksum
+  if (entry->cfg_checksum != cfg_checksum
       || entry->summary.num != expected)
     {
       static int warned = 0;
       bool warning_printed = false;
       tree id = DECL_ASSEMBLER_NAME (current_function_decl);
 
-      warning_printed = 
-	warning_at (input_location, OPT_Wcoverage_mismatch, 
+      warning_printed =
+	warning_at (input_location, OPT_Wcoverage_mismatch,
 		    "coverage mismatch for function "
 		    "%qE while reading counter %qs", id, ctr_names[counter]);
       if (warning_printed)
 	{
-	  if (entry->checksum != checksum)
-	    inform (input_location, "checksum is %x instead of %x",
-		    entry->checksum, checksum);
+	  if (entry->cfg_checksum != cfg_checksum)
+	    inform (input_location, "control flow checksum is %x instead of %x",
+		    entry->cfg_checksum, cfg_checksum);
 	  else
 	    inform (input_location, "number of counters is %d instead of %d",
 		    entry->summary.num, expected);
@@ -388,6 +394,12 @@ get_coverage_counts (unsigned counter, u
 
       return NULL;
     }
+    else if (entry->lineno_checksum != lineno_checksum)
+      {
+        warning (0, "Source location for function %qE have changed,"
+                 " the profile data may be out of date",
+                 DECL_ASSEMBLER_NAME (current_function_decl));
+      }
 
   if (summary)
     *summary = &entry->summary;
@@ -467,6 +479,7 @@ tree_coverage_counter_addr (unsigned cou
 				       NULL, NULL));
 }
 
+
 /* Generate a checksum for a string.  CHKSUM is the current
    checksum.  */
 
@@ -529,8 +542,8 @@ coverage_checksum_string (unsigned chksu
 
 /* Compute checksum for the current function.  We generate a CRC32.  */
 
-static unsigned
-compute_checksum (void)
+unsigned
+coverage_compute_lineno_checksum (void)
 {
   expanded_location xloc
     = expand_location (DECL_SOURCE_LOCATION (current_function_decl));
@@ -542,6 +555,35 @@ compute_checksum (void)
 
   return chksum;
 }
+
+/* Compute cfg checksum for the current function.
+   The checksum is calculated carefully so that
+   source code changes that doesn't affect the control flow graph
+   won't change the checksum.
+   This is to make the profile data useable across source code change.
+   The downside of this is that the compiler may use potentially
+   wrong profile data - that the source code change has non-trivial impact
+   on the validity of profile data (e.g. the reversed condition)
+   but the compiler won't detect the change and use the wrong profile data.  */
+
+unsigned
+coverage_compute_cfg_checksum (void)
+{
+  basic_block bb;
+  unsigned chksum = n_basic_blocks;
+
+  FOR_EACH_BB (bb)
+    {
+      edge e;
+      edge_iterator ei;
+      FOR_EACH_EDGE (e, ei, bb->succs)
+        {
+          chksum = crc32_byte (chksum, e->dest->index);
+        }
+    }
+
+  return chksum;
+}
 
 /* Begin output to the graph file for the current function.
    Opens the output file, if not already done. Writes the
@@ -549,7 +591,7 @@ compute_checksum (void)
    should be output.  */
 
 int
-coverage_begin_output (void)
+coverage_begin_output (unsigned lineno_checksum, unsigned cfg_checksum)
 {
   /* We don't need to output .gcno file unless we're under -ftest-coverage
      (e.g. -fprofile-arcs/generate/use don't need .gcno to work). */
@@ -575,12 +617,14 @@ coverage_begin_output (void)
 	  bbg_file_opened = 1;
 	}
 
+
       /* Announce function */
       offset = gcov_write_tag (GCOV_TAG_FUNCTION);
       gcov_write_unsigned (current_function_funcdef_no + 1);
-      gcov_write_unsigned (compute_checksum ());
+      gcov_write_unsigned (lineno_checksum);
+      gcov_write_unsigned (cfg_checksum);
       gcov_write_string (IDENTIFIER_POINTER
-			 (DECL_ASSEMBLER_NAME (current_function_decl)));
+                         (DECL_ASSEMBLER_NAME (current_function_decl)));
       gcov_write_string (xloc.file);
       gcov_write_unsigned (xloc.line);
       gcov_write_length (offset);
@@ -594,7 +638,7 @@ coverage_begin_output (void)
    error has occurred.  Save function coverage counts.  */
 
 void
-coverage_end_function (void)
+coverage_end_function (unsigned lineno_checksum, unsigned cfg_checksum)
 {
   unsigned i;
 
@@ -613,9 +657,11 @@ coverage_end_function (void)
       *functions_tail = item;
       functions_tail = &item->next;
 
+
       item->next = 0;
       item->ident = current_function_funcdef_no + 1;
-      item->checksum = compute_checksum ();
+      item->lineno_checksum = lineno_checksum;
+      item->cfg_checksum = cfg_checksum;
       for (i = 0; i != GCOV_COUNTERS; i++)
 	{
 	  item->n_ctrs[i] = fn_n_ctrs[i];
@@ -640,13 +686,18 @@ build_fn_info_type (unsigned int counter
   /* ident */
   fields = build_decl (BUILTINS_LOCATION,
 		       FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ());
-
-  /* checksum */
+  /* lineno_checksum */
   field = build_decl (BUILTINS_LOCATION,
 		      FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ());
   DECL_CHAIN (field) = fields;
   fields = field;
 
+  /* cfg checksum */
+  field = build_decl (BUILTINS_LOCATION,
+                      FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ());
+  DECL_CHAIN (field) = fields;
+  fields = field;
+
   array_type = build_int_cst (NULL_TREE, counters - 1);
   array_type = build_index_type (array_type);
   array_type = build_array_type (get_gcov_unsigned_t (), array_type);
@@ -680,10 +731,16 @@ build_fn_info_value (const struct functi
 					  function->ident));
   fields = DECL_CHAIN (fields);
 
-  /* checksum */
+  /* lineno_checksum */
+  CONSTRUCTOR_APPEND_ELT (v1, fields,
+			  build_int_cstu (get_gcov_unsigned_t (),
+					  function->lineno_checksum));
+  fields = DECL_CHAIN (fields);
+
+  /* cfg_checksum */
   CONSTRUCTOR_APPEND_ELT (v1, fields,
 			  build_int_cstu (get_gcov_unsigned_t (),
-					  function->checksum));
+					  function->cfg_checksum));
   fields = DECL_CHAIN (fields);
 
   /* counters */
Index: coverage.h
===================================================================
--- coverage.h	(revision 172802)
+++ coverage.h	(working copy)
@@ -28,11 +28,17 @@ extern void coverage_finish (void);
 
 /* Complete the coverage information for the current function. Once
    per function.  */
-extern void coverage_end_function (void);
+extern void coverage_end_function (unsigned, unsigned);
 
 /* Start outputting coverage information for the current
    function. Repeatable per function.  */
-extern int coverage_begin_output (void);
+extern int coverage_begin_output (unsigned, unsigned);
+
+/* Compute the control flow checksum for the current function.  */
+extern unsigned coverage_compute_cfg_checksum (void);
+
+/* Compute the line number checksum for the current function.  */
+extern unsigned coverage_compute_lineno_checksum (void);
 
 /* Allocate some counters. Repeatable per function.  */
 extern int coverage_counter_alloc (unsigned /*counter*/, unsigned/*num*/);
@@ -44,6 +50,8 @@ extern tree tree_coverage_counter_addr (
 /* Get all the counters for the current function.  */
 extern gcov_type *get_coverage_counts (unsigned /*counter*/,
 				       unsigned /*expected*/,
+				       unsigned /*cfg_checksum*/,
+				       unsigned /*lineno_checksum*/,
 				       const struct gcov_ctr_summary **);
 
 extern tree get_gcov_type (void);
Index: libgcov.c
===================================================================
--- libgcov.c	(revision 172802)
+++ libgcov.c	(working copy)
@@ -372,9 +372,10 @@ gcov_exit (void)
 
 	      /* Check function.  */
 	      if (tag != GCOV_TAG_FUNCTION
-		  || length != GCOV_TAG_FUNCTION_LENGTH
+	          || length != GCOV_TAG_FUNCTION_LENGTH
 		  || gcov_read_unsigned () != fi_ptr->ident
-		  || gcov_read_unsigned () != fi_ptr->checksum)
+		  || gcov_read_unsigned () != fi_ptr->lineno_checksum
+		  || gcov_read_unsigned () != fi_ptr->cfg_checksum)
 		{
 		read_mismatch:;
 		  fprintf (stderr, "profiling:%s:Merge mismatch for %s\n",
@@ -517,7 +518,8 @@ gcov_exit (void)
 	  /* Announce function.  */
 	  gcov_write_tag_length (GCOV_TAG_FUNCTION, GCOV_TAG_FUNCTION_LENGTH);
 	  gcov_write_unsigned (fi_ptr->ident);
-	  gcov_write_unsigned (fi_ptr->checksum);
+	  gcov_write_unsigned (fi_ptr->lineno_checksum);
+	  gcov_write_unsigned (fi_ptr->cfg_checksum);
 
 	  c_ix = 0;
 	  for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
Index: gcov-dump.c
===================================================================
--- gcov-dump.c	(revision 172802)
+++ gcov-dump.c	(working copy)
@@ -267,7 +267,8 @@ tag_function (const char *filename ATTRI
   unsigned long pos = gcov_position ();
 
   printf (" ident=%u", gcov_read_unsigned ());
-  printf (", checksum=0x%08x", gcov_read_unsigned ());
+  printf (", lineno_checksum=0x%08x", gcov_read_unsigned ());
+  printf (", cfg_checksum_checksum=0x%08x", gcov_read_unsigned ());
 
   if (gcov_position () - pos < length)
     {

Reply via email to