aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortejohnson <tejohnson@138bc75d-0d04-0410-961f-82ee72b054a4>2014-11-12 18:04:44 +0000
committertejohnson <tejohnson@138bc75d-0d04-0410-961f-82ee72b054a4>2014-11-12 18:04:44 +0000
commit5619fb0aa412001c88da795c85b9f51c63e260e1 (patch)
tree25d5887cbbd68b6748b1ddefd83ffa47d3cf21ad
parent30524bcded7889f3291878262ef685513dea860c (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.c8
-rw-r--r--gcc/gcov-dump.c39
-rw-r--r--gcc/gcov-io.c30
-rw-r--r--gcc/gcov-io.h16
-rw-r--r--gcc/gcov.c6
-rw-r--r--libgcc/dyn-ipa.c80
-rw-r--r--libgcc/libgcov-driver.c97
-rw-r--r--libgcc/libgcov-merge.c16
-rw-r--r--libgcc/libgcov-util.c41
-rw-r--r--libgcc/libgcov.h3
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 */