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. 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; -- This patch is available for review at http://codereview.appspot.com/4430080