diff options
author | tejohnson <tejohnson@138bc75d-0d04-0410-961f-82ee72b054a4> | 2014-11-12 18:04:44 +0000 |
---|---|---|
committer | tejohnson <tejohnson@138bc75d-0d04-0410-961f-82ee72b054a4> | 2014-11-12 18:04:44 +0000 |
commit | 5619fb0aa412001c88da795c85b9f51c63e260e1 (patch) | |
tree | 25d5887cbbd68b6748b1ddefd83ffa47d3cf21ad | |
parent | 30524bcded7889f3291878262ef685513dea860c (diff) |
Backport r215308 from google/gcc-4_9:google/gcc-4_8
2014-09-16 Teresa Johnson <tejohnson@google.com>
Google ref b/17009754.
* gcc/coverage.c (read_counts_file): Handle new section.
* gcc/gcov.c (read_count_file): Ditto.
* gcc/gcov-dump.c (dump_gcov_file): Ditto.
(tag_function): Ditto.
(tag_zero_fixup): New function.
* gcc/gcov-io.c (gcov_read_comdat_zero_fixup): Ditto.
* gcc/gcov-io.h (gcov_read_comdat_zero_fixup): Ditto.
* libgcc/dyn-ipa.c (struct checksum_alias): Change flag to pointer.
(new_checksum_alias): Ditto.
(cfg_checksum_insert): Ditto.
(checksum_set_insert): Ditto.
(gcov_build_callgraph): New parameter.
(gcov_collect_imported_modules): Add assert for duplicate gcda reads.
(gcov_fixup_counters_checksum): Change flag to pointer to flag, set it.
(__gcov_compute_module_groups): New parameter.
* libgcc/libgcov-driver.c (set_gcov_fn_fixed_up): New function.
(get_gcov_fn_fixed_up): Ditto.
(gcov_exit_merge_gcda): Handle new section.
(gcov_write_comdat_zero_fixup): Ditto.
(gcov_write_build_info): Ditto.
(gcov_write_comdat_zero_fixup): New function.
(gcov_write_func_counters): Fix indent.
(gcov_dump_module_info): Write new flag section.
* libgcc/libgcov.h (gcov_get_counter): Clear fixed-up counters.
(gcov_get_counter_target): Ditto.
* libgcc/libgcov-util.c (tag_function): Annotate fixed-up functions,
remove overly verbose output.
(tag_counters): Clear fixed-up counters.
(lipo_process_substitute_string_1): Send all verbose output to stderr.
(tag_zero_fixup): New function.
(read_gcda_file): Deallocate flag array.
(gcov_profile_scale): Send all verbose output to stderr.
(gcov_profile_normalize): Ditto.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/google/gcc-4_8@217435 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/coverage.c | 8 | ||||
-rw-r--r-- | gcc/gcov-dump.c | 39 | ||||
-rw-r--r-- | gcc/gcov-io.c | 30 | ||||
-rw-r--r-- | gcc/gcov-io.h | 16 | ||||
-rw-r--r-- | gcc/gcov.c | 6 | ||||
-rw-r--r-- | libgcc/dyn-ipa.c | 80 | ||||
-rw-r--r-- | libgcc/libgcov-driver.c | 97 | ||||
-rw-r--r-- | libgcc/libgcov-merge.c | 16 | ||||
-rw-r--r-- | libgcc/libgcov-util.c | 41 | ||||
-rw-r--r-- | libgcc/libgcov.h | 3 |
10 files changed, 294 insertions, 42 deletions
diff --git a/gcc/coverage.c b/gcc/coverage.c index 2b204e4cb62..98df86d917d 100644 --- a/gcc/coverage.c +++ b/gcc/coverage.c @@ -807,6 +807,14 @@ read_counts_file (const char *da_file_name, unsigned module_id) free (build_info_strings[i]); free (build_info_strings); } + else if (tag == GCOV_TAG_COMDAT_ZERO_FIXUP) + { + /* Zero-profile fixup flags are not used by the compiler, read and + ignore. */ + gcov_unsigned_t num_fn; + int *zero_fixup_flags = gcov_read_comdat_zero_fixup (length, &num_fn); + free (zero_fixup_flags); + } else if (GCOV_TAG_IS_COUNTER (tag) && fn_ident) { counts_entry_t **slot, *entry, elt; diff --git a/gcc/gcov-dump.c b/gcc/gcov-dump.c index 6e4613fbdc7..376da971819 100644 --- a/gcc/gcov-dump.c +++ b/gcc/gcov-dump.c @@ -41,6 +41,7 @@ static void tag_counters (const char *, unsigned, unsigned); static void tag_summary (const char *, unsigned, unsigned); static void tag_parameters (const char *, unsigned, unsigned); static void tag_build_info (const char *, unsigned, unsigned); +static void tag_zero_fixup (const char *, unsigned, unsigned); static void dump_working_sets (const char *filename ATTRIBUTE_UNUSED, const struct gcov_ctr_summary *summary); static void tag_module_info (const char *, unsigned, unsigned); @@ -58,6 +59,9 @@ static int flag_dump_positions = 0; static int flag_dump_working_sets = 0; static int flag_dump_aux_modules_only = 0; +static unsigned num_fn_info; +static int *zero_fixup_flags = NULL; + static const struct option options[] = { { "help", no_argument, NULL, 'h' }, @@ -81,6 +85,7 @@ static const tag_format_t tag_table[] = {GCOV_TAG_PROGRAM_SUMMARY, "PROGRAM_SUMMARY", tag_summary}, {GCOV_TAG_PARAMETERS, "PARAMETERS", tag_parameters}, {GCOV_TAG_MODULE_INFO, "MODULE INFO", tag_module_info}, + {GCOV_TAG_COMDAT_ZERO_FIXUP, "ZERO FIXUP", tag_zero_fixup}, {GCOV_TAG_BUILD_INFO, "BUILD INFO", tag_build_info}, {0, NULL, NULL} }; @@ -276,6 +281,8 @@ dump_gcov_file (const char *filename) printf ("%s:stamp %lu\n", filename, (unsigned long)stamp); } + num_fn_info = 0; + while (1) { gcov_position_t base, position = gcov_position (); @@ -343,6 +350,7 @@ dump_gcov_file (const char *filename) break; } } + free (zero_fixup_flags); gcov_close (); } @@ -356,7 +364,9 @@ tag_function (const char *filename ATTRIBUTE_UNUSED, printf (" placeholder"); else { - printf (" ident=%u", gcov_read_unsigned ()); + int had_fixup = zero_fixup_flags && zero_fixup_flags[num_fn_info]; + printf (" ident=%u%s", gcov_read_unsigned (), + had_fixup ? " (Was 0-count COMDAT)" : ""); printf (", lineno_checksum=0x%08x", gcov_read_unsigned ()); printf (", cfg_checksum=0x%08x", gcov_read_unsigned ()); @@ -371,6 +381,7 @@ tag_function (const char *filename ATTRIBUTE_UNUSED, printf (":%u", gcov_read_unsigned ()); } } + num_fn_info++; } static void @@ -598,6 +609,32 @@ tag_module_info (const char *filename ATTRIBUTE_UNUSED, } static void +tag_zero_fixup (const char *filename, + unsigned tag ATTRIBUTE_UNUSED, unsigned length) +{ + gcov_unsigned_t num_fns = 0; + zero_fixup_flags = gcov_read_comdat_zero_fixup (length, &num_fns); + if (!zero_fixup_flags) + { + printf ("%s:error reading zero fixup flags\n", filename); + return; + } + printf (" num_fns=%u", num_fns); + for (unsigned i = 0; i < num_fns; i++) + { + if (!(i % 32)) + { + printf ("\n"); + print_prefix (filename, 0, 0); + printf ("\t\t"); + } + if (!(i % 8)) + printf ("%s%4u:", (i%32)?" ":"", i); + printf ("%u", zero_fixup_flags[i]); + } +} + +static void tag_build_info (const char *filename, unsigned tag ATTRIBUTE_UNUSED, unsigned length) { diff --git a/gcc/gcov-io.c b/gcc/gcov-io.c index 119163dddba..ca9614951f4 100644 --- a/gcc/gcov-io.c +++ b/gcc/gcov-io.c @@ -742,6 +742,36 @@ gcov_read_summary (struct gcov_summary *summary) } } +/* Read LENGTH words (unsigned type) from a zero profile fixup record with the + number of function flags saved in NUM_FNS. Returns the int flag array, which + should be deallocated by caller, or NULL on error. */ + +GCOV_LINKAGE int * +gcov_read_comdat_zero_fixup (gcov_unsigned_t length, + gcov_unsigned_t *num_fns) +{ + unsigned ix, f_ix; + gcov_unsigned_t num = gcov_read_unsigned (); + /* The length consists of 1 word to hold the number of functions, + plus enough 32-bit words to hold 1 bit/function. */ + gcc_assert ((num + 31) / 32 + 1 == length); + int *zero_fixup_flags = (int *) xcalloc (num, sizeof (int)); + for (ix = 0; ix < length - 1; ix++) + { + gcov_unsigned_t bitvector = gcov_read_unsigned (); + f_ix = ix * 32; + while (bitvector) + { + if (bitvector & 0x1) + zero_fixup_flags[f_ix] = 1; + f_ix++; + bitvector >>= 1; + } + } + *num_fns = num; + return zero_fixup_flags; +} + /* Read NUM_STRINGS strings (as an unsigned array) in STRING_ARRAY, and return the number of words read. */ diff --git a/gcc/gcov-io.h b/gcc/gcov-io.h index 41f1bc74f00..063a8ce8203 100644 --- a/gcc/gcov-io.h +++ b/gcc/gcov-io.h @@ -129,7 +129,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see blocks they are for. The data file contains the following records. - data: {unit summary:program* build_info parameter-data function-data*}* + data: {unit summary:program* build_info zero_fixup parameter-data + function-data*}* unit: header int32:checksum function-data: announce_function present counts announce_function: header int32:ident @@ -144,6 +145,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see parameter-data: header parm-value* parm-value: string:macro_name int64:value build_info: string:info* + zero_fixup: int32:num int32:bitvector* The ANNOUNCE_FUNCTION record is the same as that in the note file, but without the source location. The COUNTS gives the @@ -159,6 +161,12 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see build. For example, it can be used to include source revision information that is useful in diagnosing profile mis-matches. + ZERO_FIXUP record contains a count of functions in the gcda file + and an array of bitvectors indexed by the function index's in the + function-data section. Each bit flags whether the function was a + COMDAT that had all-zero profiles that was fixed up by dyn-ipa + using profiles from functions with matching checksums in other modules. + This file is included by both the compiler, gcov tools and the runtime support library libgcov. IN_LIBGCOV and IN_GCOV are used to distinguish which case is which. If IN_LIBGCOV is nonzero, @@ -262,6 +270,9 @@ typedef unsigned HOST_WIDEST_INT gcov_type_unsigned; #define GCOV_TAG_COUNTER_NUM(LENGTH) ((LENGTH) / 2) #define GCOV_TAG_OBJECT_SUMMARY ((gcov_unsigned_t)0xa1000000) /* Obsolete */ #define GCOV_TAG_PROGRAM_SUMMARY ((gcov_unsigned_t)0xa3000000) +#define GCOV_TAG_COMDAT_ZERO_FIXUP ((gcov_unsigned_t)0xa9000000) +/* Ceiling divide by 32 bit word size, plus one word to hold NUM. */ +#define GCOV_TAG_COMDAT_ZERO_FIXUP_LENGTH(NUM) (1 + (NUM + 31) / 32) #define GCOV_TAG_SUMMARY_LENGTH(NUM) \ (1 + GCOV_COUNTERS_SUMMABLE * (10 + 3 * 2) + (NUM) * 5) #define GCOV_TAG_PARAMETERS ((gcov_unsigned_t)0xa5000000) @@ -475,6 +486,9 @@ GCOV_LINKAGE int gcov_close (void) ATTRIBUTE_HIDDEN; GCOV_LINKAGE gcov_unsigned_t gcov_read_unsigned (void) ATTRIBUTE_HIDDEN; GCOV_LINKAGE gcov_type gcov_read_counter (void) ATTRIBUTE_HIDDEN; GCOV_LINKAGE void gcov_read_summary (struct gcov_summary *) ATTRIBUTE_HIDDEN; +GCOV_LINKAGE int *gcov_read_comdat_zero_fixup (gcov_unsigned_t, + gcov_unsigned_t *) + ATTRIBUTE_HIDDEN; GCOV_LINKAGE char **gcov_read_build_info (gcov_unsigned_t, gcov_unsigned_t *) ATTRIBUTE_HIDDEN; GCOV_LINKAGE struct gcov_parameter_value *gcov_read_parameters (gcov_unsigned_t) diff --git a/gcc/gcov.c b/gcc/gcov.c index c70447d8f6d..87d0b884430 100644 --- a/gcc/gcov.c +++ b/gcc/gcov.c @@ -1441,6 +1441,12 @@ read_count_file (function_t *fns) free (build_info_strings[i]); free (build_info_strings); } + else if (tag == GCOV_TAG_COMDAT_ZERO_FIXUP) + { + gcov_unsigned_t num_fn; + int *zero_fixup_flags = gcov_read_comdat_zero_fixup (length, &num_fn); + free (zero_fixup_flags); + } else if (tag == GCOV_TAG_FUNCTION && !length) ; /* placeholder */ else if (tag == GCOV_TAG_FUNCTION && length == GCOV_TAG_FUNCTION_LENGTH) diff --git a/libgcc/dyn-ipa.c b/libgcc/dyn-ipa.c index 7a0d39bc1cf..82a38bc3063 100644 --- a/libgcc/dyn-ipa.c +++ b/libgcc/dyn-ipa.c @@ -107,8 +107,9 @@ struct checksum_alias struct checksum_alias *next_alias; gcov_type guid; const struct gcov_fn_info *fi_ptr; - /* Does this function have all-zero arc counts? */ - int zero_counts; + /* Non-NULL pointer to flag if this function has all-zero arc counts, to be + set if we perform fixup. */ + char *zero_count_fixup; }; /* Module info is stored in dyn_caph->sup_modules @@ -178,10 +179,10 @@ extern gcov_unsigned_t __gcov_lipo_merge_modu_edges; extern gcov_unsigned_t __gcov_lipo_weak_inclusion; #if defined(inhibit_libc) -__gcov_build_callgraph (void) {} +__gcov_build_callgraph (char **zero_counts) {} #else -int __gcov_compute_module_groups (void) ATTRIBUTE_HIDDEN; +int __gcov_compute_module_groups (char **zero_counts) ATTRIBUTE_HIDDEN; void __gcov_finalize_dyn_callgraph (void) ATTRIBUTE_HIDDEN; static void gcov_dump_callgraph (gcov_type); static void gcov_dump_cgraph_node_short (struct dyn_cgraph_node *node); @@ -376,18 +377,19 @@ lineno_checksum_get_key (const void *p) } /* Create a new checksum_alias struct for function with GUID, FI_PTR, - and ZERO_COUNTS flag. Prepends to list NEXT and returns new struct. */ + and ZERO_COUNT_FIXUP flag pointer. Prepends to list NEXT and returns + new struct. */ static struct checksum_alias * new_checksum_alias (gcov_type guid, const struct gcov_fn_info *fi_ptr, - int zero_counts, + char *zero_count_fixup, struct checksum_alias *next) { struct checksum_alias *alias = XNEW (struct checksum_alias); alias->next_alias = next; alias->fi_ptr = fi_ptr; alias->guid = guid; - alias->zero_counts = zero_counts; + alias->zero_count_fixup = zero_count_fixup; return alias; } @@ -405,11 +407,12 @@ find_cfg_checksum (struct checksum_alias_info *list, unsigned cfg_checksum) } /* Insert a new checksum_alias struct into LIST for function with - CFG_CHECKSUM and associated GUID, FI_PTR, and ZERO_COUNTS flag. */ + CFG_CHECKSUM and associated GUID, FI_PTR, and ZERO_COUNT_FIXUP + flag pointer. */ static struct checksum_alias_info * cfg_checksum_insert (unsigned cfg_checksum, gcov_type guid, - const struct gcov_fn_info *fi_ptr, int zero_counts, + const struct gcov_fn_info *fi_ptr, char *zero_count_fixup, struct checksum_alias_info *list) { struct checksum_alias_info *alias_info; @@ -417,7 +420,8 @@ cfg_checksum_insert (unsigned cfg_checksum, gcov_type guid, if (alias_info) { gcc_assert (alias_info->alias_list); - alias_info->alias_list = new_checksum_alias (guid, fi_ptr, zero_counts, + alias_info->alias_list = new_checksum_alias (guid, fi_ptr, + zero_count_fixup, alias_info->alias_list); return list; } @@ -426,7 +430,8 @@ cfg_checksum_insert (unsigned cfg_checksum, gcov_type guid, alias_info = XNEW (struct checksum_alias_info); alias_info->next_cfg_checksum = list; alias_info->cfg_checksum = cfg_checksum; - alias_info->alias_list = new_checksum_alias (guid, fi_ptr, zero_counts, + alias_info->alias_list = new_checksum_alias (guid, fi_ptr, + zero_count_fixup, NULL); return alias_info; } @@ -434,12 +439,12 @@ cfg_checksum_insert (unsigned cfg_checksum, gcov_type guid, /* Insert a new checksum_alias struct into lineno_pointer_sets for function with LINENO_CHECKSUM and CFG_CHECKSUM with associated GUID, FI_PTR, and - ZERO_COUNTS flag. */ + ZERO_COUNT_FIXUP flag pointer. */ static void checksum_set_insert (unsigned lineno_checksum, unsigned cfg_checksum, gcov_type guid, const struct gcov_fn_info *fi_ptr, - int zero_counts) + char *zero_count_fixup) { struct dyn_pointer_set *p = the_dyn_call_graph.lineno_pointer_sets; if (!p) @@ -450,7 +455,7 @@ checksum_set_insert (unsigned lineno_checksum, unsigned cfg_checksum, if (*m) { (*m)->cfg_checksum_list = cfg_checksum_insert (cfg_checksum, guid, - fi_ptr, zero_counts, + fi_ptr, zero_count_fixup, (*m)->cfg_checksum_list); } else @@ -458,7 +463,8 @@ checksum_set_insert (unsigned lineno_checksum, unsigned cfg_checksum, *m = XNEW (struct lineno_checksum_alias); (*m)->lineno_checksum = lineno_checksum; (*m)->cfg_checksum_list = cfg_checksum_insert (cfg_checksum, guid, - fi_ptr, zero_counts, NULL); + fi_ptr, zero_count_fixup, + NULL); p->n_elements++; } } @@ -803,10 +809,10 @@ gcov_build_callgraph_ic_fn (struct dyn_cgraph_node *caller, } } -/* Build the dynamic call graph. */ +/* Build the dynamic call graph and update ZERO_COUNTS flags. */ static void -gcov_build_callgraph (void) +gcov_build_callgraph (char **zero_counts) { struct gcov_info *gi_ptr; unsigned m_ix; @@ -854,9 +860,19 @@ gcov_build_callgraph (void) if (total_arc_count != 0) the_dyn_call_graph.num_nodes_executed++; if (fixup_type) - checksum_set_insert (fi_ptr->lineno_checksum, - fi_ptr->cfg_checksum, caller->guid, - fi_ptr, total_arc_count == 0); + { + char *zero_count_fixup = NULL; + /* Passing in a non-NULL zero_count_fixup pointer + indicates that the counts were all zero for this + function, and the fixup routine will set the flag + if the function's counters are updated to non-zero + values. */ + if (total_arc_count == 0) + zero_count_fixup = &zero_counts[m_ix][f_ix]; + checksum_set_insert (fi_ptr->lineno_checksum, + fi_ptr->cfg_checksum, caller->guid, + fi_ptr, zero_count_fixup); + } } ci_ptr++; } @@ -1253,7 +1269,14 @@ gcov_collect_imported_modules (const void *value, out_array = (struct gcov_import_mod_array *) data1; if (m->imp_mod != out_array->importing_module) + { out_array->imported_modules[out_array->len++] = m; + /* Sanity check that the importing (primary) module is not + actually the same as the new aux module. This could happen if + we accidentally read in the same gcda file twice. */ + gcc_assert (m->imp_mod->mod_info->ident != + out_array->importing_module->mod_info->ident); + } return 1; } @@ -2930,7 +2953,7 @@ gcov_fixup_counters_checksum (const struct checksum_alias_info *info, for (alias = info->alias_list; alias; alias = alias->next_alias) { - if (alias->zero_counts) + if (alias->zero_count_fixup) { found = 1; break; @@ -2945,7 +2968,7 @@ gcov_fixup_counters_checksum (const struct checksum_alias_info *info, for (alias = info->alias_list; alias; alias = alias->next_alias) { - if (alias->zero_counts) + if (alias->zero_count_fixup) continue; merge_ctrs (merged_ctrs, alias->fi_ptr->ctrs, alias->guid); found = 1; @@ -2963,9 +2986,10 @@ gcov_fixup_counters_checksum (const struct checksum_alias_info *info, for (alias = info->alias_list; alias; alias = alias->next_alias) { - if (!alias->zero_counts) + if (!alias->zero_count_fixup) continue; copy_ctrs (alias->fi_ptr->ctrs, alias->guid, merged_ctrs); + *alias->zero_count_fixup = 1; } return 1; @@ -3013,11 +3037,13 @@ gcov_fixup_zero_counters (void) return changed; } -/* Compute module groups needed for L-IPO compilation. Returns 1 if any - counter fixups were applied, requiring a profile rewrite, 0 otherwise. */ +/* Compute module groups needed for L-IPO compilation. The ZERO_COUNTS + flags are set for functions with zero count fixups applied. Returns 1 + if any counter fixups were applied, requiring a profile rewrite, + 0 otherwise. */ int -__gcov_compute_module_groups (void) +__gcov_compute_module_groups (char **zero_counts) { gcov_type cut_off_count; char *seed = getenv ("LIPO_RANDOM_GROUPING"); @@ -3064,7 +3090,7 @@ __gcov_compute_module_groups (void) fixup_type = atoi (do_fixup); /* First compute dynamic call graph. */ - gcov_build_callgraph (); + gcov_build_callgraph (zero_counts); cut_off_count = gcov_compute_cutoff_count (); diff --git a/libgcc/libgcov-driver.c b/libgcc/libgcov-driver.c index 00029026a18..01a76fd9399 100644 --- a/libgcc/libgcov-driver.c +++ b/libgcc/libgcov-driver.c @@ -160,6 +160,24 @@ get_gcov_list (void) return __gcov_list; } +/* Flag if the current function being read was marked as having fixed-up + zero counters. */ +static int __gcov_curr_fn_fixed_up; + +/* Set function fixed up flag. */ +void +set_gcov_fn_fixed_up (int fixed_up) +{ + __gcov_curr_fn_fixed_up = fixed_up; +} + +/* Return function fixed up flag. */ +int +get_gcov_fn_fixed_up (void) +{ + return __gcov_curr_fn_fixed_up; +} + /* Size of the longest file name. */ static size_t gcov_max_filename = 0; @@ -173,7 +191,7 @@ static int gcov_sampling_period_initialized = 0; static gcov_unsigned_t gcov_cur_module_id = 0; /* Dynamic call graph build and form module groups. */ -int __gcov_compute_module_groups (void) ATTRIBUTE_HIDDEN; +int __gcov_compute_module_groups (char **zero_counts) ATTRIBUTE_HIDDEN; void __gcov_finalize_dyn_callgraph (void) ATTRIBUTE_HIDDEN; /* Add an unsigned value to the current crc */ @@ -540,6 +558,7 @@ gcov_exit_merge_gcda (struct gcov_info *gi_ptr, unsigned t_ix, f_ix; int error = 0; struct gcov_summary_buffer **sum_tail = &sum_buffer; + int *zero_fixup_flags = NULL; version = gcov_read_unsigned (); if (!gcov_version (gi_ptr, version, gi_filename)) @@ -609,6 +628,21 @@ gcov_exit_merge_gcda (struct gcov_info *gi_ptr, tag = gcov_read_unsigned (); } + if (tag == GCOV_TAG_COMDAT_ZERO_FIXUP) + { + length = gcov_read_unsigned (); + gcov_unsigned_t num_fns = 0; + zero_fixup_flags = gcov_read_comdat_zero_fixup (length, &num_fns); + if (!zero_fixup_flags) + { + gcov_error ("profiling:%s:Error reading zero fixup flags\n", + gi_filename); + return -1; + } + + tag = gcov_read_unsigned (); + } + /* Merge execution counts for each function. */ for (f_ix = 0; f_ix != gi_ptr->n_functions; f_ix++, tag = gcov_read_unsigned ()) @@ -619,6 +653,9 @@ gcov_exit_merge_gcda (struct gcov_info *gi_ptr, if (tag != GCOV_TAG_FUNCTION) goto read_mismatch; + if (zero_fixup_flags) + set_gcov_fn_fixed_up (zero_fixup_flags[f_ix]); + length = gcov_read_unsigned (); if (!length) /* This function did not appear in the other program. @@ -662,6 +699,7 @@ gcov_exit_merge_gcda (struct gcov_info *gi_ptr, gi_filename, f_ix + 1 ? "function" : "summaries"); return -1; } + free (zero_fixup_flags); return 0; @@ -672,6 +710,34 @@ read_error:; } + +/* Write NUM_FNS ZERO_COUNTS fixup flags to a gcda file starting from its + current location. */ + +static void +gcov_write_comdat_zero_fixup (char *zero_counts, unsigned num_fns) +{ + unsigned f_ix; + gcov_unsigned_t len = GCOV_TAG_COMDAT_ZERO_FIXUP_LENGTH (num_fns); + gcov_write_tag_length (GCOV_TAG_COMDAT_ZERO_FIXUP, len); + + gcov_write_unsigned (num_fns); + gcov_unsigned_t bitvector = 0, b_ix = 0; + for (f_ix = 0; f_ix != num_fns; f_ix++) + { + if (zero_counts[f_ix]) + bitvector |= 1 << b_ix; + if (++b_ix == 32) + { + gcov_write_unsigned (bitvector); + b_ix = 0; + bitvector = 0; + } + } + if (b_ix > 0) + gcov_write_unsigned (bitvector); +} + /* Write build_info strings from GI_PTR to a gcda file starting from its current location. */ @@ -1044,9 +1110,24 @@ gcov_dump_module_info (struct gcov_filename_aux *gf) { struct gcov_info *gi_ptr; + unsigned max_module_id = 0; + for (gi_ptr = __gcov_list; gi_ptr; gi_ptr = gi_ptr->next) + { + unsigned mod_id = gi_ptr->mod_info->ident; + if (max_module_id < mod_id) + max_module_id = mod_id; + } + char **zero_counts = (char **) xcalloc (max_module_id, sizeof (char *)); + for (gi_ptr = __gcov_list; gi_ptr; gi_ptr = gi_ptr->next) + { + unsigned mod_id = gi_ptr->mod_info->ident; + zero_counts[mod_id-1] = (char *) xcalloc (gi_ptr->n_functions, + sizeof (char)); + } + /* Compute the module groups and record whether there were any counter fixups applied that require rewriting the counters. */ - int changed = __gcov_compute_module_groups (); + int changed = __gcov_compute_module_groups (zero_counts); /* Now write out module group info. */ for (gi_ptr = __gcov_list; gi_ptr; gi_ptr = gi_ptr->next) @@ -1069,8 +1150,15 @@ gcov_dump_module_info (struct gcov_filename_aux *gf) gcov_position_t eof_pos = gi_ptr->eof_pos; gcov_rewrite (); gcov_seek (summary_end_pos); + + unsigned mod_id = gi_ptr->mod_info->ident; + gcov_write_comdat_zero_fixup (zero_counts[mod_id-1], + gi_ptr->n_functions); + gcov_position_t zero_fixup_eof_pos = gcov_position (); + gcov_write_func_counters (gi_ptr); - gcc_assert (eof_pos == gi_ptr->eof_pos); + gcc_assert (eof_pos + (zero_fixup_eof_pos - summary_end_pos) + == gi_ptr->eof_pos); } } else @@ -1089,8 +1177,11 @@ gcov_dump_module_info (struct gcov_filename_aux *gf) "profiling:%s:Error writing\n", gi_filename); gcov_write_import_file (gi_filename, gi_ptr); + free (zero_counts[gi_ptr->mod_info->ident-1]); } + free (zero_counts); + __gcov_finalize_dyn_callgraph (); } diff --git a/libgcc/libgcov-merge.c b/libgcc/libgcov-merge.c index 27d8ad5c77e..cbeb86c08b6 100644 --- a/libgcc/libgcov-merge.c +++ b/libgcc/libgcov-merge.c @@ -49,7 +49,13 @@ static inline gcov_type gcov_get_counter (void) { #ifndef IN_GCOV_TOOL - return gcov_read_counter (); + if (get_gcov_fn_fixed_up ()) + { + gcov_read_counter (); + return 0; + } + else + return gcov_read_counter (); #else return gcov_read_counter_mem () * gcov_get_merge_weight (); #endif @@ -59,7 +65,13 @@ static inline gcov_type gcov_get_counter_target (void) { #ifndef IN_GCOV_TOOL - return gcov_read_counter (); + if (get_gcov_fn_fixed_up ()) + { + gcov_read_counter (); + return 0; + } + else + return gcov_read_counter (); #else return gcov_read_counter_mem (); #endif diff --git a/libgcc/libgcov-util.c b/libgcc/libgcov-util.c index 547e0ed7d7d..de5bcf9e615 100644 --- a/libgcc/libgcov-util.c +++ b/libgcc/libgcov-util.c @@ -70,6 +70,7 @@ static void tag_lines (unsigned, unsigned); static void tag_counters (unsigned, unsigned); static void tag_summary (unsigned, unsigned); static void tag_module_info (unsigned, unsigned); +static void tag_zero_fixup (unsigned, unsigned); /* The gcov_info for the first module. */ static struct gcov_info *curr_gcov_info; @@ -92,6 +93,8 @@ static int k_ctrs_types; /* The longest length of all the filenames. */ static int max_filename_len; +static int *zero_fixup_flags = NULL; + /* Merge functions for counters. Similar to __gcov_dyn_ipa_merge_* functions in dyn-ipa.c, which were derived from these, except the versions in dyn-ipa are used when merging from another array. */ @@ -148,6 +151,7 @@ static const tag_format_t tag_table[] = {GCOV_TAG_OBJECT_SUMMARY, "OBJECT_SUMMARY", tag_summary}, {GCOV_TAG_PROGRAM_SUMMARY, "PROGRAM_SUMMARY", tag_summary}, {GCOV_TAG_MODULE_INFO, "MODULE INFO", tag_module_info}, + {GCOV_TAG_COMDAT_ZERO_FIXUP, "ZERO FIXUP", tag_zero_fixup}, {0, NULL, NULL} }; @@ -174,14 +178,18 @@ tag_function (unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED) k_ctrs[i].num = 0; k_ctrs_types = 0; + if (zero_fixup_flags) + { + set_gcov_fn_fixed_up (zero_fixup_flags[num_fn_info]); + if (get_gcov_fn_fixed_up () && verbose) + fprintf (stderr, "Function id=%d fixed up\n", curr_fn_info->ident); + } + curr_fn_info->key = curr_gcov_info; curr_fn_info->ident = gcov_read_unsigned (); curr_fn_info->lineno_checksum = gcov_read_unsigned (); curr_fn_info->cfg_checksum = gcov_read_unsigned (); num_fn_info++; - - if (verbose) - fprintf (stdout, "tag one function id=%d\n", curr_fn_info->ident); } /* Handler for reading block tag. */ @@ -228,7 +236,13 @@ tag_counters (unsigned tag, unsigned length) gcc_assert (values); for (ix = 0; ix != n_counts; ix++) - values[ix] = gcov_read_counter (); + { + gcov_type val = gcov_read_counter (); + if (!get_gcov_fn_fixed_up ()) + values[ix] = val; + else + values[ix] = 0; + } } /* Handler for reading summary tag. */ @@ -325,7 +339,7 @@ lipo_process_substitute_string_1 (char *input_str, char *t; if (verbose) - printf ("Substitute: %s \n", input_str); + fprintf (stderr, "Substitute: %s \n", input_str); t = (char*) xmalloc (strlen (input_str) + 1 + strlen (new_str) - strlen (cur_str)); *p = 0; @@ -334,7 +348,7 @@ lipo_process_substitute_string_1 (char *input_str, strcat (t, new_str); strcat (t, p + strlen (cur_str)); if (verbose) - printf (" --> %s\n", t); + fprintf (stderr, " --> %s\n", t); return t; } @@ -399,6 +413,16 @@ tag_module_info (unsigned tag ATTRIBUTE_UNUSED, unsigned length) free (mod_info); } +/* Handler for reading the COMDAT zero-profile fixup section. */ + +static void +tag_zero_fixup (unsigned tag ATTRIBUTE_UNUSED, unsigned length) +{ + gcov_unsigned_t num_fns = 0; + zero_fixup_flags = gcov_read_comdat_zero_fixup (length, &num_fns); + gcc_assert (zero_fixup_flags); +} + /* Read the content of a gcda file FILENAME, and return a gcov_info data structure. Program level summary CURRENT_SUMMARY will also be updated. */ @@ -526,6 +550,7 @@ read_gcda_file (const char *filename) } read_gcda_finalize (obj_info); + free (zero_fixup_flags); gcov_close (); return obj_info; @@ -1015,7 +1040,7 @@ gcov_profile_scale (struct gcov_info *profile, float scale_factor, int n, int d) unsigned f_ix; if (verbose) - fprintf (stdout, "scale_factor is %f\n", scale_factor); + fprintf (stderr, "scale_factor is %f\n", scale_factor); /* Scaling the counters. */ for (gi_ptr = profile; gi_ptr; gi_ptr = gi_ptr->next) @@ -1082,7 +1107,7 @@ gcov_profile_normalize (struct gcov_info *profile, gcov_type max_val) scale_factor = (float)max_val / curr_max_val; if (verbose) - fprintf (stdout, "max_val is %lld\n", (long long) curr_max_val); + fprintf (stderr, "max_val is %lld\n", (long long) curr_max_val); return gcov_profile_scale (profile, scale_factor, 0, 0); } diff --git a/libgcc/libgcov.h b/libgcc/libgcov.h index f91e7faff58..cda8ee57f1a 100644 --- a/libgcc/libgcov.h +++ b/libgcc/libgcov.h @@ -333,6 +333,9 @@ gcov_get_sorted_import_module_array (struct gcov_info *mod_info, unsigned *len) /*staic void gcov_rewrite (void); */ GCOV_LINKAGE void gcov_seek (gcov_position_t /*position*/) ATTRIBUTE_HIDDEN; GCOV_LINKAGE void gcov_truncate (void) ATTRIBUTE_HIDDEN; + +extern void set_gcov_fn_fixed_up (int fixed_up); +extern int get_gcov_fn_fixed_up (void); #endif /* !inhibit_libc */ |