Patchwork [google] backport r17317,r17347,r17342 to google/main (issue4430080)

login
register
mail settings
Submitter Xinliang David Li
Date May 4, 2011, 12:28 a.m.
Message ID <20110504002803.DB5E62066A@syzygy.mtv.corp.google.com>
Download mbox | patch
Permalink /patch/93934/
State New
Headers show

Comments

Xinliang David Li - May 4, 2011, 12:28 a.m.
Backport patches r17342, r173177, and r173147 from trunk to google/main + some minor cleanups for problems found in test.

Tested: bootstrap + regression test + SPEC06 LIPO testing.

Backport r173177
2011-05-03  David Li  <davidxl@google.com>

	* tree-profile.c (init_ic_make_global_vars): Set
	tls attribute on ic vars.
	* coverage.c (coverage_end_function): Initialize
	function_list with zero.

Backport r173147
2011-05-03  David Li  <davidxl@google.com>

	* tree.c (crc32_string): Use crc32_byte.
	(crc32_byte): New function.
	* tree.h (crc32_byte): New function.
	* gcov.c (read_graph_file): Handle new cfg_cksum.
	(read_count_file): Ditto.
	* profile.c (instrument_values): Ditto.
	(get_exec_counts): Ditto.
	(read_profile_edge_counts): Ditto.
	(compute_branch_probabilities): Ditto.
	(compute_value_histograms): Ditto.
	(branch_prob): Ditto.
	(end_branch_prob): Ditto.
	* coverage.c (read_counts_file): Ditto.
	(get_coverage_counts): Ditto.
	(tree_coverage_counter_addr): Ditto.
	(coverage_checksum_string): Ditto.
	(coverage_begin_output): Ditto.
	(coverage_end_function): Ditto.
	(build_fn_info_type): Ditto.
	(build_fn_info_value): Ditto.
	* libgcov.c (gcov_exit): Ditto.
	* gcov-dump.c (tag_function): Ditto.
	(compute_checksum): Remove.

2011-05-03  David Li  <davidxl@google.com>

	* l-ipo.c (promote_static_var_or_func): Keep initializer
	for externalized aux module variables.
	(process_module_scope_static_var): Keep initializer
	for promoted static vars to allow ccp.

Backport r17342
2011-05-03  Xinliang David Li  <davidxl@google.com>

	* gcc.dg/tree-ssa/integer-addr.c: New test.
	* gcc.dg/tree-ssa/alias_bug.c: New test.


--
This patch is available for review at http://codereview.appspot.com/4430080

Patch

Index: tree.c
===================================================================
--- tree.c	(revision 173345)
+++ tree.c	(working copy)
@@ -8489,14 +8489,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)
@@ -8507,6 +8505,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;
@@ -8530,8 +8540,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 173345)
+++ tree.h	(working copy)
@@ -4948,6 +4948,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 173345)
+++ 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;
@@ -809,12 +817,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 ();
@@ -822,7 +832,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;
 
@@ -1109,7 +1120,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: gcov-io.h
===================================================================
--- gcov-io.h	(revision 173345)
+++ 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
@@ -330,7 +332,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)
@@ -495,10 +497,12 @@  extern unsigned primary_module_id;
    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 */
   gcov_unsigned_t dc_offset;    /* direct call offset */
   unsigned n_ctrs[0];		/* instrumented counters */
 };
Index: profile.c
===================================================================
--- profile.c	(revision 173345)
+++ 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.
 
@@ -238,10 +231,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;
@@ -258,7 +253,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;
 
@@ -448,10 +444,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;
@@ -460,7 +458,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.  */
@@ -778,10 +776,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];
@@ -809,7 +810,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];
@@ -912,6 +914,7 @@  branch_prob (void)
   unsigned num_instrumented;
   struct edge_list *el;
   histogram_values values = NULL;
+  unsigned cfg_checksum, lineno_checksum;
 
   total_num_times_called++;
 
@@ -1065,11 +1068,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;
 
@@ -1086,7 +1097,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;
 
@@ -1127,7 +1138,7 @@  branch_prob (void)
     }
 
   /* Line numbers.  */
-  if (coverage_begin_output ())
+  if (coverage_begin_output (lineno_checksum, cfg_checksum))
     {
       gcov_position_t offset;
 
@@ -1186,9 +1197,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 ();
@@ -1216,7 +1227,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
@@ -1383,4 +1394,3 @@  end_branch_prob (void)
 	}
     }
 }
-
Index: coverage.c
===================================================================
--- coverage.c	(revision 173345)
+++ coverage.c	(working copy)
@@ -56,6 +56,7 @@  along with GCC; see the file COPYING3.  
 #include "intl.h"
 #include "l-ipo.h"
 
+#include "gcov-io.h"
 #include "gcov-io.c"
 #include "params.h"
 #include "dbgcnt.h"
@@ -65,7 +66,8 @@  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.  */
   unsigned dc_offset;            /* offset of counters to direct calls.  */
 };
@@ -85,7 +87,8 @@  typedef struct counts_entry
   unsigned ctr;
 
   /* Store  */
-  unsigned checksum;
+  unsigned lineno_checksum;
+  unsigned cfg_checksum;
   gcov_type *counts;
   struct gcov_ctr_summary summary;
 
@@ -148,8 +151,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 (const char *, unsigned);
-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);
@@ -286,7 +287,6 @@  static void
 read_counts_file (const char *da_file_name, unsigned module_id)
 {
   gcov_unsigned_t fn_ident = 0;
-  gcov_unsigned_t checksum = -1;
   counts_entry_t *summaried = NULL;
   unsigned seen_summary = 0;
   gcov_unsigned_t tag;
@@ -294,6 +294,8 @@  read_counts_file (const char *da_file_na
   unsigned module_infos_read = 0;
   struct pointer_set_t *modset = 0;
   unsigned max_group = PARAM_VALUE (PARAM_MAX_LIPO_GROUP);
+  unsigned lineno_checksum = 0;
+  unsigned cfg_checksum = 0;
 
   if (max_group == 0)
     max_group = (unsigned) -1;
@@ -347,7 +349,8 @@  read_counts_file (const char *da_file_na
       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
@@ -399,22 +402,24 @@  read_counts_file (const char *da_file_na
 	      *slot = entry = XCNEW (counts_entry_t);
 	      entry->ident = elt.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 ("Profile data for function %u is corrupted", fn_ident);
+	      error ("checksum is (%x,%x) instead of (%x,%x)",
+		     entry->lineno_checksum, entry->cfg_checksum,
+		     lineno_checksum, cfg_checksum);
 	      htab_delete (counts_hash);
 	      break;
 	    }
 	  else if (entry->summary.num != n_counts)
 	    {
-	      error ("coverage mismatch for function %u while reading execution counters",
-		     fn_ident);
+	      error ("Profile data for function %u is corrupted", fn_ident);
 	      error ("number of counters is %d instead of %d", entry->summary.num, n_counts);
 	      htab_delete (counts_hash);
 	      break;
@@ -550,46 +555,14 @@  read_counts_file (const char *da_file_na
    FUNC. EXPECTED is the number of expected counter entries.  */
 
 static counts_entry_t *
-get_coverage_counts_entry (struct function *func,
-                           unsigned counter, unsigned expected)
+get_coverage_counts_entry (struct function *func, unsigned counter)
 {
-  counts_entry_t *entry, *new_entry, elt;
-  tree decl;
-  struct cgraph_node *real_node;
+  counts_entry_t *entry, elt;
 
   elt.ident = FUNC_DECL_GLOBAL_ID (func);
   elt.ctr = counter;
   entry = (counts_entry_t *) htab_find (counts_hash, &elt);
-  if (entry)
-    return entry;
-
-  if (!L_IPO_COMP_MODE)
-    return NULL;
 
-  decl = func->decl;
-  real_node = cgraph_lipo_get_resolved_node_1 (decl, false);
-  if (real_node && 0)
-    {
-      counts_entry_t real_elt;
-      real_elt.ident = FUNC_DECL_GLOBAL_ID (DECL_STRUCT_FUNCTION (real_node->decl));
-      real_elt.ctr = counter;
-      entry = (counts_entry_t *) htab_find (counts_hash, &real_elt);
-      if (entry && expected == entry->summary.num)
-        {
-          /* Make a copy.  */
-          counts_entry_t **slot;
-          slot = (counts_entry_t **) htab_find_slot (counts_hash, &elt, INSERT);
-          gcc_assert (slot && !*slot);
-          *slot = new_entry = XCNEW (counts_entry_t);
-          new_entry->ident = elt.ident;
-          new_entry->ctr = elt.ctr;
-          new_entry->checksum = entry->checksum;
-          new_entry->summary.num = entry->summary.num;
-          new_entry->counts = XCNEWVEC (gcov_type, entry->summary.num);
-          memcpy (new_entry->counts, entry->counts, sizeof (gcov_type) * entry->summary.num);
-          entry = new_entry;
-        }
-    }
   return entry;
 }
 
@@ -597,10 +570,10 @@  get_coverage_counts_entry (struct functi
 
 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;
-  gcov_unsigned_t checksum = -1;
 
   /* No hash table, no counts.  */
   if (!counts_hash)
@@ -615,7 +588,7 @@  get_coverage_counts (unsigned counter, u
       return NULL;
     }
 
-  entry = get_coverage_counts_entry (cfun, counter, expected);
+  entry = get_coverage_counts_entry (cfun, counter);
 
   if (!entry)
     {
@@ -625,26 +598,21 @@  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, 
-		    "coverage mismatch for function "
-		    "%qE while reading counter %qs", id, ctr_names[counter]);
+      warning_printed =
+	warning_at (input_location, OPT_Wcoverage_mismatch,
+		    "The control flow of function %qE does not match "
+		    "its profile data (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);
-	  else
-	    inform (input_location, "number of counters is %d instead of %d",
-		    entry->summary.num, expected);
+	 inform (input_location, "Use -Wno-error=coverage-mismatch to tolerate "
+	 	 "the mismatch but performance may drop if the function is hot");
 	  
 	  if (!seen_error ()
 	      && !warned++)
@@ -661,6 +629,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;
@@ -762,6 +736,7 @@  tree_coverage_counter_addr (unsigned cou
 				       NULL, NULL));
 }
 
+
 /* Generate a checksum for a string.  CHKSUM is the current
    checksum.  */
 
@@ -825,8 +800,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)
 {
   tree name;
   expanded_location xloc
@@ -857,6 +832,36 @@  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;
+      chksum = crc32_byte (chksum, bb->index);
+      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
@@ -864,7 +869,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). */
@@ -890,12 +895,14 @@  coverage_begin_output (void)
 	  bbg_file_opened = 1;
 	}
 
+
       /* Announce function */
       offset = gcov_write_tag (GCOV_TAG_FUNCTION);
       gcov_write_unsigned (FUNC_DECL_FUNC_ID (cfun));
-      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);
@@ -909,7 +916,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;
 
@@ -928,9 +935,11 @@  coverage_end_function (void)
       *functions_tail = item;
       functions_tail = &item->next;
 
+
       item->next = 0;
       item->ident = FUNC_DECL_FUNC_ID (cfun);
-      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];
@@ -978,7 +987,8 @@  coverage_dc_end_function (void)
 	  functions_tail = &item->next;
 	  item->next = 0;
 	  item->ident = FUNC_DECL_FUNC_ID (cfun);
-	  item->checksum = compute_checksum ();
+	  item->lineno_checksum = coverage_compute_lineno_checksum ();
+	  item->cfg_checksum = coverage_compute_cfg_checksum ();
 	  for (i = 0; i < GCOV_COUNTERS; i++)
 	    item->n_ctrs[i] = 0;
 	}
@@ -1005,13 +1015,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;
+
   /* dc offset */
   field = build_decl (BUILTINS_LOCATION,
 		      FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ());
@@ -1051,10 +1066,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);
 
   /* dc offset */
Index: coverage.h
===================================================================
--- coverage.h	(revision 173345)
+++ 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 **);
 /* Get all the counters for the current function without warning.  */
 extern gcov_type *get_coverage_counts_no_warn (struct function *, 
Index: tree-profile.c
===================================================================
--- tree-profile.c	(revision 173345)
+++ tree-profile.c	(working copy)
@@ -46,6 +46,8 @@  along with GCC; see the file COPYING3.  
 #include "output.h"
 #include "l-ipo.h"
 #include "profile.h"
+#include "target.h"
+#include "output.h"
 
 static GTY(()) tree gcov_type_node;
 static GTY(()) tree gcov_type_tmp_var;
@@ -92,8 +94,9 @@  init_ic_make_global_vars (void)
 		      ptr_void);
       TREE_PUBLIC (ic_void_ptr_var) = 1;
       DECL_EXTERNAL (ic_void_ptr_var) = 1;
-      DECL_TLS_MODEL (ic_void_ptr_var) =
-	decl_default_tls_model (ic_void_ptr_var);
+      if (targetm.have_tls)
+        DECL_TLS_MODEL (ic_void_ptr_var) =
+          decl_default_tls_model (ic_void_ptr_var);
 
       gcov_type_ptr = build_pointer_type (get_gcov_type ());
       ic_gcov_type_ptr_var 
@@ -102,8 +105,9 @@  init_ic_make_global_vars (void)
 		      gcov_type_ptr);
       TREE_PUBLIC (ic_gcov_type_ptr_var) = 1;
       DECL_EXTERNAL (ic_gcov_type_ptr_var) = 1;
-      DECL_TLS_MODEL (ic_gcov_type_ptr_var) =
-	decl_default_tls_model (ic_gcov_type_ptr_var);
+      if (targetm.have_tls)
+        DECL_TLS_MODEL (ic_gcov_type_ptr_var) =
+          decl_default_tls_model (ic_gcov_type_ptr_var);
     }
   else
     {
@@ -114,6 +118,9 @@  init_ic_make_global_vars (void)
       TREE_STATIC (ic_void_ptr_var) = 1;
       TREE_PUBLIC (ic_void_ptr_var) = 0;
       DECL_INITIAL (ic_void_ptr_var) = NULL;
+      if (targetm.have_tls)
+        DECL_TLS_MODEL (ic_void_ptr_var) =
+          decl_default_tls_model (ic_void_ptr_var);
 
       gcov_type_ptr = build_pointer_type (get_gcov_type ());
       ic_gcov_type_ptr_var 
@@ -123,6 +130,9 @@  init_ic_make_global_vars (void)
       TREE_STATIC (ic_gcov_type_ptr_var) = 1;
       TREE_PUBLIC (ic_gcov_type_ptr_var) = 0;
       DECL_INITIAL (ic_gcov_type_ptr_var) = NULL;
+      if (targetm.have_tls)
+        DECL_TLS_MODEL (ic_gcov_type_ptr_var) =
+          decl_default_tls_model (ic_gcov_type_ptr_var);
     }
 
   DECL_ARTIFICIAL (ic_void_ptr_var) = 1;
Index: l-ipo.c
===================================================================
--- l-ipo.c	(revision 173345)
+++ l-ipo.c	(working copy)
@@ -1770,8 +1770,9 @@  promote_static_var_func (unsigned module
         {
           TREE_STATIC (decl) = 0;
           DECL_EXTERNAL (decl) = 1;
-          DECL_INITIAL (decl) = 0;
-	  DECL_CONTEXT (decl) = 0;
+          /* Keep the initializer to allow const prop.  */
+          /* DECL_INITIAL (decl) = 0; */
+          DECL_CONTEXT (decl) = 0;
         }
       /* else
          Function body will be deleted later before expansion.  */
@@ -1800,7 +1801,8 @@  process_module_scope_static_var (struct 
 	    {
 	      DECL_EXTERNAL (decl) = 1;
 	      TREE_STATIC (decl) = 0;
-	      DECL_INITIAL (decl) = NULL;
+              /* Keep the initializer to allow const prop.  */
+	      /* DECL_INITIAL (decl) = NULL; */
 	      if (DECL_CONTEXT (decl))
                 {
                   DECL_ASSEMBLER_NAME (decl);
Index: libgcov.c
===================================================================
--- libgcov.c	(revision 173345)
+++ libgcov.c	(working copy)
@@ -507,9 +507,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",
@@ -652,7 +653,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 173345)
+++ gcov-dump.c	(working copy)
@@ -328,7 +328,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)
     {
       const char *name;