mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-19 03:40:26 +08:00
libgcov.c (struct gcov_fn_buffer): New struct.
libgcc/ * libgcov.c (struct gcov_fn_buffer): New struct. (buffer_fn_data): New helper. (gcov_exit): Rework for new gcov data structures. gcc/ * gcov.c (object_summary): Replace with ... (object_runs): ... this. (process_file): Remove functions with no data. (generate_results): Ignore files with no lines. (release_function): New helper, broken out of ... (release_structures): ... here. Use it. (read_count_file): Adjust for new data file format. (output_lines): Use object_runs. * gcov-io.h (GCOV_TAG_OBJECT_SUMMARY): Obsolete. (struct gcov_ctr_info): Move definition. (struct gcov_fn_info): Add key field, use gcov_ctr_info for trailing array. (struct gcov_info): Add merge function array, remove mask and counts. Trailing array is array of pointers to function info. * coverage.c (struct function_list): Replace counter numbers with counter arrays. Add fndecl field. GTYify. (counts_entry): Remove chain workspace. (functions_head): GTYify. (prg_n_ctrs): Remove. (fn_v_ctrs): New. (tree_ctr_tables): Remove. (read_counts_file): Cope with blank entries and expect program summaries before functions. Don't warn on missing entries. (coverage_counter_alloc): Allocate individual function arrays. (tree_coverage_counter_ref, tree_coverage_counter_addr): Adjust for individual function arrays. (coverage_end_function): GTYify function list object. Finalize function's counter arrays. (build_var): New. Create a counter-related variable with appropriate linkage. (build_fn_info_type): Adjust for new runtime structure. (build_fn_info_value): Rename to ... (build_fn_info): ... here. Build new format data. (build_ctr_info_type, build_ctr_info_value): Remove. (build_info_type): New. Build new format data structure. (build_info): Adjust for new format data. (create_coverage): Likewise. * gcov-dump.c (tag_function): Recognize placeholders. gcc/testsuite/ * gcc.dg/profile-dir-1.c: Adjust final scan. * gcc.dg/profile-dir-2.c: Adjust final scan. * gcc.dg/profile-dir-3.c: Adjust final scan. * gcc.misc-tests/gcov.exp: Adjust regexp. * gcc.misc-tests/gcov-12.c: New. * gcc.misc-tests/gcov-13.c: New. * gcc.misc-tests/gcovpart-13b.c: New. * gcc.misc-tests/gcov-14.c: New. From-SVN: r181105
This commit is contained in:
parent
74155a6f37
commit
5366b18679
@ -1,3 +1,44 @@
|
||||
2011-11-07 Nathan Sidwell <nathan@acm.org>
|
||||
|
||||
* gcov.c (object_summary): Replace with ...
|
||||
(object_runs): ... this.
|
||||
(process_file): Remove functions with no data.
|
||||
(generate_results): Ignore files with no lines.
|
||||
(release_function): New helper, broken out of ...
|
||||
(release_structures): ... here. Use it.
|
||||
(read_count_file): Adjust for new data file format.
|
||||
(output_lines): Use object_runs.
|
||||
* gcov-io.h (GCOV_TAG_OBJECT_SUMMARY): Obsolete.
|
||||
(struct gcov_ctr_info): Move definition.
|
||||
(struct gcov_fn_info): Add key field, use gcov_ctr_info for
|
||||
trailing array.
|
||||
(struct gcov_info): Add merge function array, remove mask and
|
||||
counts. Trailing array is array of pointers to function info.
|
||||
* coverage.c (struct function_list): Replace counter numbers with
|
||||
counter arrays. Add fndecl field. GTYify.
|
||||
(counts_entry): Remove chain workspace.
|
||||
(functions_head): GTYify.
|
||||
(prg_n_ctrs): Remove.
|
||||
(fn_v_ctrs): New.
|
||||
(tree_ctr_tables): Remove.
|
||||
(read_counts_file): Cope with blank entries and expect program
|
||||
summaries before functions. Don't warn on missing entries.
|
||||
(coverage_counter_alloc): Allocate individual function arrays.
|
||||
(tree_coverage_counter_ref, tree_coverage_counter_addr): Adjust
|
||||
for individual function arrays.
|
||||
(coverage_end_function): GTYify function list object. Finalize
|
||||
function's counter arrays.
|
||||
(build_var): New. Create a counter-related variable with
|
||||
appropriate linkage.
|
||||
(build_fn_info_type): Adjust for new runtime structure.
|
||||
(build_fn_info_value): Rename to ...
|
||||
(build_fn_info): ... here. Build new format data.
|
||||
(build_ctr_info_type, build_ctr_info_value): Remove.
|
||||
(build_info_type): New. Build new format data structure.
|
||||
(build_info): Adjust for new format data.
|
||||
(create_coverage): Likewise.
|
||||
* gcov-dump.c (tag_function): Recognize placeholders.
|
||||
|
||||
2011-11-07 Georg-Johann Lay <avr@gjlay.de>
|
||||
|
||||
* config/avr/constraints.md (Cm2): New constraint for int -2.
|
||||
|
671
gcc/coverage.c
671
gcc/coverage.c
@ -1,6 +1,6 @@
|
||||
/* Read and write coverage files, and associated functionality.
|
||||
Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, 1999,
|
||||
2000, 2001, 2003, 2004, 2005, 2007, 2008, 2009, 2010
|
||||
2000, 2001, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011
|
||||
Free Software Foundation, Inc.
|
||||
Contributed by James E. Wilson, UC Berkeley/Cygnus Support;
|
||||
based on some ideas from Dain Samples of UC Berkeley.
|
||||
@ -54,13 +54,14 @@ along with GCC; see the file COPYING3. If not see
|
||||
#include "gcov-io.h"
|
||||
#include "gcov-io.c"
|
||||
|
||||
struct function_list
|
||||
struct GTY((chain_next ("%h.next"))) function_list
|
||||
{
|
||||
struct function_list *next; /* next function */
|
||||
unsigned ident; /* function ident */
|
||||
unsigned lineno_checksum; /* function lineno checksum */
|
||||
unsigned cfg_checksum; /* function cfg checksum */
|
||||
unsigned n_ctrs[GCOV_COUNTERS];/* number of counters. */
|
||||
tree fn_decl; /* the function decl */
|
||||
tree ctr_vars[GCOV_COUNTERS]; /* counter variables. */
|
||||
};
|
||||
|
||||
/* Counts information for a function. */
|
||||
@ -75,22 +76,18 @@ typedef struct counts_entry
|
||||
unsigned cfg_checksum;
|
||||
gcov_type *counts;
|
||||
struct gcov_ctr_summary summary;
|
||||
|
||||
/* Workspace */
|
||||
struct counts_entry *chain;
|
||||
|
||||
} counts_entry_t;
|
||||
|
||||
static struct function_list *functions_head = 0;
|
||||
static GTY(()) struct function_list *functions_head = 0;
|
||||
static struct function_list **functions_tail = &functions_head;
|
||||
static unsigned no_coverage = 0;
|
||||
|
||||
/* Cumulative counter information for whole program. */
|
||||
static unsigned prg_ctr_mask; /* Mask of counter types generated. */
|
||||
static unsigned prg_n_ctrs[GCOV_COUNTERS]; /* Total counters allocated. */
|
||||
|
||||
/* Counter information for current function. */
|
||||
static unsigned fn_ctr_mask; /* Mask of counters used. */
|
||||
static GTY(()) tree fn_v_ctrs[GCOV_COUNTERS]; /* counter variables. */
|
||||
static unsigned fn_n_ctrs[GCOV_COUNTERS]; /* Counters allocated. */
|
||||
static unsigned fn_b_ctrs[GCOV_COUNTERS]; /* Allocation base. */
|
||||
|
||||
@ -105,9 +102,6 @@ static char *da_file_name;
|
||||
/* Hash table of count data. */
|
||||
static htab_t counts_hash = NULL;
|
||||
|
||||
/* Trees representing the counter table arrays. */
|
||||
static GTY(()) tree tree_ctr_tables[GCOV_COUNTERS];
|
||||
|
||||
/* The names of merge functions for counters. */
|
||||
static const char *const ctr_merge_functions[GCOV_COUNTERS] = GCOV_MERGE_FUNCTIONS;
|
||||
static const char *const ctr_names[GCOV_COUNTERS] = GCOV_COUNTER_NAMES;
|
||||
@ -117,11 +111,11 @@ static hashval_t htab_counts_entry_hash (const void *);
|
||||
static int htab_counts_entry_eq (const void *, const void *);
|
||||
static void htab_counts_entry_del (void *);
|
||||
static void read_counts_file (void);
|
||||
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);
|
||||
static tree build_ctr_info_value (unsigned, tree);
|
||||
static tree build_gcov_info (void);
|
||||
static tree build_var (tree, tree, int);
|
||||
static void build_fn_info_type (tree, unsigned, tree);
|
||||
static tree build_fn_info (const struct function_list *, tree, tree);
|
||||
static void build_info_type (tree, unsigned, tree);
|
||||
static tree build_info (tree, tree, tree, unsigned);
|
||||
static void create_coverage (void);
|
||||
|
||||
/* Return the type node for gcov_type. */
|
||||
@ -172,8 +166,8 @@ static void
|
||||
read_counts_file (void)
|
||||
{
|
||||
gcov_unsigned_t fn_ident = 0;
|
||||
counts_entry_t *summaried = NULL;
|
||||
unsigned seen_summary = 0;
|
||||
struct gcov_summary summary;
|
||||
unsigned new_summary = 1;
|
||||
gcov_unsigned_t tag;
|
||||
int is_error = 0;
|
||||
unsigned lineno_checksum = 0;
|
||||
@ -216,42 +210,34 @@ read_counts_file (void)
|
||||
offset = gcov_position ();
|
||||
if (tag == GCOV_TAG_FUNCTION)
|
||||
{
|
||||
fn_ident = gcov_read_unsigned ();
|
||||
lineno_checksum = gcov_read_unsigned ();
|
||||
cfg_checksum = gcov_read_unsigned ();
|
||||
if (seen_summary)
|
||||
if (length)
|
||||
{
|
||||
/* We have already seen a summary, this means that this
|
||||
new function begins a new set of program runs. We
|
||||
must unlink the summaried chain. */
|
||||
counts_entry_t *entry, *chain;
|
||||
|
||||
for (entry = summaried; entry; entry = chain)
|
||||
{
|
||||
chain = entry->chain;
|
||||
entry->chain = NULL;
|
||||
}
|
||||
summaried = NULL;
|
||||
seen_summary = 0;
|
||||
fn_ident = gcov_read_unsigned ();
|
||||
lineno_checksum = gcov_read_unsigned ();
|
||||
cfg_checksum = gcov_read_unsigned ();
|
||||
}
|
||||
else
|
||||
fn_ident = lineno_checksum = cfg_checksum = 0;
|
||||
new_summary = 1;
|
||||
}
|
||||
else if (tag == GCOV_TAG_PROGRAM_SUMMARY)
|
||||
{
|
||||
counts_entry_t *entry;
|
||||
struct gcov_summary summary;
|
||||
struct gcov_summary sum;
|
||||
unsigned ix;
|
||||
|
||||
gcov_read_summary (&summary);
|
||||
seen_summary = 1;
|
||||
for (entry = summaried; entry; entry = entry->chain)
|
||||
if (new_summary)
|
||||
memset (&summary, 0, sizeof (summary));
|
||||
|
||||
gcov_read_summary (&sum);
|
||||
for (ix = 0; ix != GCOV_COUNTERS_SUMMABLE; ix++)
|
||||
{
|
||||
struct gcov_ctr_summary *csum = &summary.ctrs[entry->ctr];
|
||||
|
||||
entry->summary.runs += csum->runs;
|
||||
entry->summary.sum_all += csum->sum_all;
|
||||
if (entry->summary.run_max < csum->run_max)
|
||||
entry->summary.run_max = csum->run_max;
|
||||
entry->summary.sum_max += csum->sum_max;
|
||||
summary.ctrs[ix].runs += sum.ctrs[ix].runs;
|
||||
summary.ctrs[ix].sum_all += sum.ctrs[ix].sum_all;
|
||||
if (summary.ctrs[ix].run_max < sum.ctrs[ix].run_max)
|
||||
summary.ctrs[ix].run_max = sum.ctrs[ix].run_max;
|
||||
summary.ctrs[ix].sum_max += sum.ctrs[ix].sum_max;
|
||||
}
|
||||
new_summary = 0;
|
||||
}
|
||||
else if (GCOV_TAG_IS_COUNTER (tag) && fn_ident)
|
||||
{
|
||||
@ -272,6 +258,7 @@ read_counts_file (void)
|
||||
entry->ctr = elt.ctr;
|
||||
entry->lineno_checksum = lineno_checksum;
|
||||
entry->cfg_checksum = cfg_checksum;
|
||||
entry->summary = summary.ctrs[elt.ctr];
|
||||
entry->summary.num = n_counts;
|
||||
entry->counts = XCNEWVEC (gcov_type, n_counts);
|
||||
}
|
||||
@ -298,15 +285,13 @@ read_counts_file (void)
|
||||
ctr_names[elt.ctr], fn_ident);
|
||||
goto skip_merge;
|
||||
}
|
||||
|
||||
if (elt.ctr < GCOV_COUNTERS_SUMMABLE
|
||||
/* This should always be true for a just allocated entry,
|
||||
and always false for an existing one. Check this way, in
|
||||
case the gcov file is corrupt. */
|
||||
&& (!entry->chain || summaried != entry))
|
||||
else
|
||||
{
|
||||
entry->chain = summaried;
|
||||
summaried = entry;
|
||||
entry->summary.runs += summary.ctrs[elt.ctr].runs;
|
||||
entry->summary.sum_all += summary.ctrs[elt.ctr].sum_all;
|
||||
if (entry->summary.run_max < summary.ctrs[elt.ctr].run_max)
|
||||
entry->summary.run_max = summary.ctrs[elt.ctr].run_max;
|
||||
entry->summary.sum_max += summary.ctrs[elt.ctr].sum_max;
|
||||
}
|
||||
for (ix = 0; ix != n_counts; ix++)
|
||||
entry->counts[ix] += gcov_read_counter ();
|
||||
@ -350,13 +335,12 @@ get_coverage_counts (unsigned counter, unsigned expected,
|
||||
elt.ident = current_function_funcdef_no + 1;
|
||||
elt.ctr = counter;
|
||||
entry = (counts_entry_t *) htab_find (counts_hash, &elt);
|
||||
if (!entry)
|
||||
{
|
||||
warning (0, "no coverage for function %qE found",
|
||||
DECL_ASSEMBLER_NAME (current_function_decl));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!entry || !entry->summary.num)
|
||||
/* The function was not emitted, or is weak and not chosen in the
|
||||
final executable. Silently fail, because there's nothing we
|
||||
can do about it. */
|
||||
return NULL;
|
||||
|
||||
if (entry->cfg_checksum != cfg_checksum
|
||||
|| entry->summary.num != expected)
|
||||
{
|
||||
@ -366,11 +350,11 @@ get_coverage_counts (unsigned counter, unsigned expected,
|
||||
|
||||
warning_printed =
|
||||
warning_at (input_location, OPT_Wcoverage_mismatch,
|
||||
"The control flow of function %qE does not match "
|
||||
"the control flow of function %qE does not match "
|
||||
"its profile data (counter %qs)", id, ctr_names[counter]);
|
||||
if (warning_printed)
|
||||
{
|
||||
inform (input_location, "Use -Wno-error=coverage-mismatch to tolerate "
|
||||
inform (input_location, "use -Wno-error=coverage-mismatch to tolerate "
|
||||
"the mismatch but performance may drop if the function is hot");
|
||||
|
||||
if (!seen_error ()
|
||||
@ -388,12 +372,12 @@ get_coverage_counts (unsigned counter, unsigned expected,
|
||||
|
||||
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));
|
||||
}
|
||||
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;
|
||||
@ -413,28 +397,17 @@ coverage_counter_alloc (unsigned counter, unsigned num)
|
||||
if (!num)
|
||||
return 1;
|
||||
|
||||
if (!tree_ctr_tables[counter])
|
||||
if (!fn_v_ctrs[counter])
|
||||
{
|
||||
/* Generate and save a copy of this so it can be shared. Leave
|
||||
the index type unspecified for now; it will be set after all
|
||||
functions have been compiled. */
|
||||
char buf[20];
|
||||
tree gcov_type_node = get_gcov_type ();
|
||||
tree gcov_type_array_type
|
||||
= build_array_type (gcov_type_node, NULL_TREE);
|
||||
tree_ctr_tables[counter]
|
||||
= build_decl (BUILTINS_LOCATION,
|
||||
VAR_DECL, NULL_TREE, gcov_type_array_type);
|
||||
TREE_STATIC (tree_ctr_tables[counter]) = 1;
|
||||
ASM_GENERATE_INTERNAL_LABEL (buf, "LPBX", counter + 1);
|
||||
DECL_NAME (tree_ctr_tables[counter]) = get_identifier (buf);
|
||||
DECL_ALIGN (tree_ctr_tables[counter]) = TYPE_ALIGN (gcov_type_node);
|
||||
tree array_type = build_array_type (get_gcov_type (), NULL_TREE);
|
||||
|
||||
if (dump_file)
|
||||
fprintf (dump_file, "Using data file %s\n", da_file_name);
|
||||
fn_v_ctrs[counter]
|
||||
= build_var (current_function_decl, array_type, counter);
|
||||
}
|
||||
|
||||
fn_b_ctrs[counter] = fn_n_ctrs[counter];
|
||||
fn_n_ctrs[counter] += num;
|
||||
|
||||
fn_ctr_mask |= 1 << counter;
|
||||
return 1;
|
||||
}
|
||||
@ -447,10 +420,11 @@ tree_coverage_counter_ref (unsigned counter, unsigned no)
|
||||
tree gcov_type_node = get_gcov_type ();
|
||||
|
||||
gcc_assert (no < fn_n_ctrs[counter] - fn_b_ctrs[counter]);
|
||||
no += prg_n_ctrs[counter] + fn_b_ctrs[counter];
|
||||
|
||||
no += fn_b_ctrs[counter];
|
||||
|
||||
/* "no" here is an array index, scaled to bytes later. */
|
||||
return build4 (ARRAY_REF, gcov_type_node, tree_ctr_tables[counter],
|
||||
return build4 (ARRAY_REF, gcov_type_node, fn_v_ctrs[counter],
|
||||
build_int_cst (integer_type_node, no), NULL, NULL);
|
||||
}
|
||||
|
||||
@ -462,13 +436,11 @@ tree_coverage_counter_addr (unsigned counter, unsigned no)
|
||||
tree gcov_type_node = get_gcov_type ();
|
||||
|
||||
gcc_assert (no < fn_n_ctrs[counter] - fn_b_ctrs[counter]);
|
||||
no += prg_n_ctrs[counter] + fn_b_ctrs[counter];
|
||||
|
||||
TREE_ADDRESSABLE (tree_ctr_tables[counter]) = 1;
|
||||
no += fn_b_ctrs[counter];
|
||||
|
||||
/* "no" here is an array index, scaled to bytes later. */
|
||||
return build_fold_addr_expr (build4 (ARRAY_REF, gcov_type_node,
|
||||
tree_ctr_tables[counter],
|
||||
fn_v_ctrs[counter],
|
||||
build_int_cst (integer_type_node, no),
|
||||
NULL, NULL));
|
||||
}
|
||||
@ -647,78 +619,159 @@ coverage_end_function (unsigned lineno_checksum, unsigned cfg_checksum)
|
||||
{
|
||||
struct function_list *item;
|
||||
|
||||
item = XCNEW (struct function_list);
|
||||
|
||||
*functions_tail = item;
|
||||
functions_tail = &item->next;
|
||||
|
||||
item = ggc_alloc_function_list ();
|
||||
|
||||
item->next = 0;
|
||||
item->ident = current_function_funcdef_no + 1;
|
||||
item->lineno_checksum = lineno_checksum;
|
||||
item->cfg_checksum = cfg_checksum;
|
||||
item->fn_decl = current_function_decl;
|
||||
for (i = 0; i != GCOV_COUNTERS; i++)
|
||||
{
|
||||
item->n_ctrs[i] = fn_n_ctrs[i];
|
||||
prg_n_ctrs[i] += fn_n_ctrs[i];
|
||||
fn_n_ctrs[i] = fn_b_ctrs[i] = 0;
|
||||
tree var = fn_v_ctrs[i];
|
||||
|
||||
item->ctr_vars[i] = var;
|
||||
if (var)
|
||||
{
|
||||
tree array_type = build_index_type (size_int (fn_n_ctrs[i] - 1));
|
||||
array_type = build_array_type (get_gcov_type (), array_type);
|
||||
TREE_TYPE (var) = array_type;
|
||||
DECL_SIZE (var) = TYPE_SIZE (array_type);
|
||||
DECL_SIZE_UNIT (var) = TYPE_SIZE_UNIT (array_type);
|
||||
varpool_finalize_decl (var);
|
||||
}
|
||||
fn_b_ctrs[i] = fn_n_ctrs[i] = 0;
|
||||
fn_v_ctrs[i] = NULL_TREE;
|
||||
}
|
||||
prg_ctr_mask |= fn_ctr_mask;
|
||||
fn_ctr_mask = 0;
|
||||
/* If the function is extern (i.e. extern inline), then we won't
|
||||
be outputting it, so don't chain it onto the function list. */
|
||||
if (!DECL_EXTERNAL (item->fn_decl))
|
||||
{
|
||||
*functions_tail = item;
|
||||
functions_tail = &item->next;
|
||||
}
|
||||
}
|
||||
bbg_function_announced = 0;
|
||||
}
|
||||
|
||||
/* Creates the gcov_fn_info RECORD_TYPE. */
|
||||
/* Build a coverage variable of TYPE for function FN_DECL. If COUNTER
|
||||
>= 0 it is a counter array, and thus local. Otherwise it is the
|
||||
function structure and needs to be globalized. All cases must be
|
||||
in the same comdat group as FN_DECL. */
|
||||
|
||||
static tree
|
||||
build_fn_info_type (unsigned int counters)
|
||||
build_var (tree fn_decl, tree type, int counter)
|
||||
{
|
||||
tree type = lang_hooks.types.make_type (RECORD_TYPE);
|
||||
tree var = build_decl (BUILTINS_LOCATION, VAR_DECL, NULL_TREE, type);
|
||||
tree fn_name = DECL_ASSEMBLER_NAME (fn_decl);
|
||||
char *buf = (char *)alloca (IDENTIFIER_LENGTH (fn_name) + 10);
|
||||
|
||||
if (counter >= 0)
|
||||
TREE_STATIC (var) = 1;
|
||||
else
|
||||
{
|
||||
TREE_PUBLIC (var) = TREE_PUBLIC (fn_decl);
|
||||
TREE_STATIC (var) = TREE_STATIC (fn_decl);
|
||||
}
|
||||
TREE_ADDRESSABLE (var) = 1;
|
||||
DECL_ALIGN (var) = TYPE_ALIGN (type);
|
||||
|
||||
if (counter < 0)
|
||||
sprintf (buf, "__gcov__%s", IDENTIFIER_POINTER (fn_name));
|
||||
else
|
||||
sprintf (buf, "__gcov%u_%s", counter, IDENTIFIER_POINTER (fn_name));
|
||||
DECL_NAME (var) = get_identifier (buf);
|
||||
|
||||
/* Initialize assembler name so we can stream out. */
|
||||
if (TREE_PUBLIC (var))
|
||||
DECL_ASSEMBLER_NAME (var);
|
||||
|
||||
DECL_WEAK (var) = TREE_PUBLIC (var) && DECL_WEAK (fn_decl);
|
||||
DECL_COMDAT (var) = DECL_COMDAT (fn_decl);
|
||||
DECL_COMDAT_GROUP (var) = DECL_COMDAT_GROUP (fn_decl);
|
||||
|
||||
return var;
|
||||
}
|
||||
|
||||
/* Creates the gcov_fn_info RECORD_TYPE. */
|
||||
|
||||
static void
|
||||
build_fn_info_type (tree type, unsigned counters, tree gcov_info_type)
|
||||
{
|
||||
tree ctr_info = lang_hooks.types.make_type (RECORD_TYPE);
|
||||
tree field, fields;
|
||||
tree array_type;
|
||||
|
||||
gcc_assert (counters);
|
||||
|
||||
/* ctr_info::num */
|
||||
field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
|
||||
get_gcov_unsigned_t ());
|
||||
fields = field;
|
||||
|
||||
/* ctr_info::values */
|
||||
field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
|
||||
build_pointer_type (get_gcov_type ()));
|
||||
DECL_CHAIN (field) = fields;
|
||||
fields = field;
|
||||
|
||||
finish_builtin_struct (ctr_info, "__gcov_ctr_info", fields, NULL_TREE);
|
||||
|
||||
/* key */
|
||||
field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
|
||||
build_pointer_type (build_qualified_type
|
||||
(gcov_info_type, TYPE_QUAL_CONST)));
|
||||
fields = field;
|
||||
|
||||
/* ident */
|
||||
fields = build_decl (BUILTINS_LOCATION,
|
||||
FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ());
|
||||
field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
|
||||
get_gcov_unsigned_t ());
|
||||
DECL_CHAIN (field) = fields;
|
||||
fields = field;
|
||||
|
||||
/* lineno_checksum */
|
||||
field = build_decl (BUILTINS_LOCATION,
|
||||
FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ());
|
||||
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 ());
|
||||
field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
|
||||
get_gcov_unsigned_t ());
|
||||
DECL_CHAIN (field) = fields;
|
||||
fields = field;
|
||||
|
||||
array_type = build_index_type (size_int (counters - 1));
|
||||
array_type = build_array_type (get_gcov_unsigned_t (), array_type);
|
||||
array_type = build_array_type (ctr_info, array_type);
|
||||
|
||||
/* counters */
|
||||
field = build_decl (BUILTINS_LOCATION,
|
||||
FIELD_DECL, NULL_TREE, array_type);
|
||||
field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE, array_type);
|
||||
DECL_CHAIN (field) = fields;
|
||||
fields = field;
|
||||
|
||||
finish_builtin_struct (type, "__gcov_fn_info", fields, NULL_TREE);
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
/* Creates a CONSTRUCTOR for a gcov_fn_info. FUNCTION is
|
||||
the function being processed and TYPE is the gcov_fn_info
|
||||
RECORD_TYPE. */
|
||||
RECORD_TYPE. KEY is the object file key. */
|
||||
|
||||
static tree
|
||||
build_fn_info_value (const struct function_list *function, tree type)
|
||||
build_fn_info (const struct function_list *function, tree type, tree key)
|
||||
{
|
||||
tree fields = TYPE_FIELDS (type);
|
||||
tree ctr_type;
|
||||
unsigned ix;
|
||||
VEC(constructor_elt,gc) *v1 = NULL;
|
||||
VEC(constructor_elt,gc) *v2 = NULL;
|
||||
|
||||
/* key */
|
||||
CONSTRUCTOR_APPEND_ELT (v1, fields,
|
||||
build1 (ADDR_EXPR, TREE_TYPE (fields), key));
|
||||
fields = DECL_CHAIN (fields);
|
||||
|
||||
/* ident */
|
||||
CONSTRUCTOR_APPEND_ELT (v1, fields,
|
||||
build_int_cstu (get_gcov_unsigned_t (),
|
||||
@ -738,240 +791,194 @@ build_fn_info_value (const struct function_list *function, tree type)
|
||||
fields = DECL_CHAIN (fields);
|
||||
|
||||
/* counters */
|
||||
ctr_type = TREE_TYPE (TREE_TYPE (fields));
|
||||
for (ix = 0; ix != GCOV_COUNTERS; ix++)
|
||||
if (prg_ctr_mask & (1 << ix))
|
||||
CONSTRUCTOR_APPEND_ELT (v2, NULL,
|
||||
build_int_cstu (get_gcov_unsigned_t (),
|
||||
function->n_ctrs[ix]));
|
||||
{
|
||||
VEC(constructor_elt,gc) *ctr = NULL;
|
||||
tree var = function->ctr_vars[ix];
|
||||
unsigned count = 0;
|
||||
|
||||
if (var)
|
||||
count
|
||||
= tree_low_cst (TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (var))), 0)
|
||||
+ 1;
|
||||
|
||||
CONSTRUCTOR_APPEND_ELT (ctr, TYPE_FIELDS (ctr_type),
|
||||
build_int_cstu (get_gcov_unsigned_t (),
|
||||
count));
|
||||
|
||||
if (var)
|
||||
CONSTRUCTOR_APPEND_ELT (ctr, DECL_CHAIN (TYPE_FIELDS (ctr_type)),
|
||||
build_fold_addr_expr (var));
|
||||
|
||||
CONSTRUCTOR_APPEND_ELT (v2, NULL, build_constructor (ctr_type, ctr));
|
||||
}
|
||||
|
||||
CONSTRUCTOR_APPEND_ELT (v1, fields,
|
||||
build_constructor (TREE_TYPE (fields), v2));
|
||||
|
||||
return build_constructor (type, v1);
|
||||
}
|
||||
|
||||
/* Creates the gcov_ctr_info RECORD_TYPE. */
|
||||
/* Creaste gcov_info_struct. N_FUNCS is the number of functions in
|
||||
the trailing array. */
|
||||
|
||||
static tree
|
||||
build_ctr_info_type (void)
|
||||
static void
|
||||
build_info_type (tree type, unsigned n_funcs, tree fn_info_type)
|
||||
{
|
||||
tree type = lang_hooks.types.make_type (RECORD_TYPE);
|
||||
tree field, fields = NULL_TREE;
|
||||
tree gcov_ptr_type = build_pointer_type (get_gcov_type ());
|
||||
tree gcov_merge_fn_type;
|
||||
|
||||
/* counters */
|
||||
field = build_decl (BUILTINS_LOCATION,
|
||||
FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ());
|
||||
DECL_CHAIN (field) = fields;
|
||||
fields = field;
|
||||
|
||||
/* values */
|
||||
field = build_decl (BUILTINS_LOCATION,
|
||||
FIELD_DECL, NULL_TREE, gcov_ptr_type);
|
||||
DECL_CHAIN (field) = fields;
|
||||
fields = field;
|
||||
|
||||
/* merge */
|
||||
gcov_merge_fn_type =
|
||||
build_function_type_list (void_type_node,
|
||||
gcov_ptr_type, get_gcov_unsigned_t (),
|
||||
NULL_TREE);
|
||||
field = build_decl (BUILTINS_LOCATION,
|
||||
FIELD_DECL, NULL_TREE,
|
||||
build_pointer_type (gcov_merge_fn_type));
|
||||
DECL_CHAIN (field) = fields;
|
||||
fields = field;
|
||||
|
||||
finish_builtin_struct (type, "__gcov_ctr_info", fields, NULL_TREE);
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
/* Creates a CONSTRUCTOR for a gcov_ctr_info. COUNTER is
|
||||
the counter being processed and TYPE is the gcov_ctr_info
|
||||
RECORD_TYPE. */
|
||||
|
||||
static tree
|
||||
build_ctr_info_value (unsigned int counter, tree type)
|
||||
{
|
||||
tree fields = TYPE_FIELDS (type);
|
||||
tree fn;
|
||||
VEC(constructor_elt,gc) *v = NULL;
|
||||
|
||||
/* counters */
|
||||
CONSTRUCTOR_APPEND_ELT (v, fields,
|
||||
build_int_cstu (get_gcov_unsigned_t (),
|
||||
prg_n_ctrs[counter]));
|
||||
fields = DECL_CHAIN (fields);
|
||||
|
||||
if (prg_n_ctrs[counter])
|
||||
{
|
||||
tree array_type;
|
||||
|
||||
array_type = build_int_cstu (get_gcov_unsigned_t (),
|
||||
prg_n_ctrs[counter] - 1);
|
||||
array_type = build_index_type (array_type);
|
||||
array_type = build_array_type (TREE_TYPE (TREE_TYPE (fields)),
|
||||
array_type);
|
||||
|
||||
TREE_TYPE (tree_ctr_tables[counter]) = array_type;
|
||||
DECL_SIZE (tree_ctr_tables[counter]) = TYPE_SIZE (array_type);
|
||||
DECL_SIZE_UNIT (tree_ctr_tables[counter]) = TYPE_SIZE_UNIT (array_type);
|
||||
varpool_finalize_decl (tree_ctr_tables[counter]);
|
||||
|
||||
CONSTRUCTOR_APPEND_ELT (v, fields,
|
||||
build1 (ADDR_EXPR, TREE_TYPE (fields),
|
||||
tree_ctr_tables[counter]));
|
||||
}
|
||||
else
|
||||
CONSTRUCTOR_APPEND_ELT (v, fields, null_pointer_node);
|
||||
fields = DECL_CHAIN (fields);
|
||||
|
||||
fn = build_decl (BUILTINS_LOCATION,
|
||||
FUNCTION_DECL,
|
||||
get_identifier (ctr_merge_functions[counter]),
|
||||
TREE_TYPE (TREE_TYPE (fields)));
|
||||
DECL_EXTERNAL (fn) = 1;
|
||||
TREE_PUBLIC (fn) = 1;
|
||||
DECL_ARTIFICIAL (fn) = 1;
|
||||
TREE_NOTHROW (fn) = 1;
|
||||
DECL_ASSEMBLER_NAME (fn); /* Initialize assembler name so we can stream out. */
|
||||
CONSTRUCTOR_APPEND_ELT (v, fields, build1 (ADDR_EXPR, TREE_TYPE (fields), fn));
|
||||
|
||||
return build_constructor (type, v);
|
||||
}
|
||||
|
||||
/* Creates the gcov_info RECORD_TYPE and initializer for it. Returns a
|
||||
CONSTRUCTOR. */
|
||||
|
||||
static tree
|
||||
build_gcov_info (void)
|
||||
{
|
||||
unsigned n_ctr_types, ix;
|
||||
tree type, const_type;
|
||||
tree fn_info_type, fn_info_value = NULL_TREE;
|
||||
tree fn_info_ptr_type;
|
||||
tree ctr_info_type, ctr_info_ary_type, ctr_info_value = NULL_TREE;
|
||||
tree field, fields = NULL_TREE;
|
||||
tree filename_string;
|
||||
int da_file_name_len;
|
||||
unsigned n_fns;
|
||||
const struct function_list *fn;
|
||||
tree string_type;
|
||||
VEC(constructor_elt,gc) *v1 = NULL;
|
||||
VEC(constructor_elt,gc) *v2 = NULL;
|
||||
|
||||
/* Count the number of active counters. */
|
||||
for (n_ctr_types = 0, ix = 0; ix != GCOV_COUNTERS; ix++)
|
||||
if (prg_ctr_mask & (1 << ix))
|
||||
n_ctr_types++;
|
||||
|
||||
type = lang_hooks.types.make_type (RECORD_TYPE);
|
||||
const_type = build_qualified_type (type, TYPE_QUAL_CONST);
|
||||
tree merge_fn_type, fn_info_array;
|
||||
|
||||
gcc_assert (n_funcs);
|
||||
|
||||
/* Version ident */
|
||||
field = build_decl (BUILTINS_LOCATION,
|
||||
FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ());
|
||||
field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
|
||||
get_gcov_unsigned_t ());
|
||||
DECL_CHAIN (field) = fields;
|
||||
fields = field;
|
||||
CONSTRUCTOR_APPEND_ELT (v1, field,
|
||||
build_int_cstu (TREE_TYPE (field), GCOV_VERSION));
|
||||
|
||||
/* next -- NULL */
|
||||
field = build_decl (BUILTINS_LOCATION,
|
||||
FIELD_DECL, NULL_TREE, build_pointer_type (const_type));
|
||||
/* next pointer */
|
||||
field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
|
||||
build_pointer_type (build_qualified_type
|
||||
(type, TYPE_QUAL_CONST)));
|
||||
DECL_CHAIN (field) = fields;
|
||||
fields = field;
|
||||
CONSTRUCTOR_APPEND_ELT (v1, field, null_pointer_node);
|
||||
|
||||
/* stamp */
|
||||
field = build_decl (BUILTINS_LOCATION,
|
||||
FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ());
|
||||
field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
|
||||
get_gcov_unsigned_t ());
|
||||
DECL_CHAIN (field) = fields;
|
||||
fields = field;
|
||||
CONSTRUCTOR_APPEND_ELT (v1, field,
|
||||
build_int_cstu (TREE_TYPE (field), local_tick));
|
||||
|
||||
/* Filename */
|
||||
string_type = build_pointer_type (build_qualified_type (char_type_node,
|
||||
TYPE_QUAL_CONST));
|
||||
field = build_decl (BUILTINS_LOCATION,
|
||||
FIELD_DECL, NULL_TREE, string_type);
|
||||
field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
|
||||
build_pointer_type (build_qualified_type
|
||||
(char_type_node, TYPE_QUAL_CONST)));
|
||||
DECL_CHAIN (field) = fields;
|
||||
fields = field;
|
||||
|
||||
/* merge fn array */
|
||||
merge_fn_type
|
||||
= build_function_type_list (void_type_node,
|
||||
build_pointer_type (get_gcov_type ()),
|
||||
get_gcov_unsigned_t (), NULL_TREE);
|
||||
merge_fn_type
|
||||
= build_array_type (build_pointer_type (merge_fn_type),
|
||||
build_index_type (size_int (GCOV_COUNTERS - 1)));
|
||||
field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
|
||||
merge_fn_type);
|
||||
DECL_CHAIN (field) = fields;
|
||||
fields = field;
|
||||
|
||||
/* n_functions */
|
||||
field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
|
||||
get_gcov_unsigned_t ());
|
||||
DECL_CHAIN (field) = fields;
|
||||
fields = field;
|
||||
|
||||
/* function_info pointer array */
|
||||
fn_info_type = build_pointer_type
|
||||
(build_qualified_type (fn_info_type, TYPE_QUAL_CONST));
|
||||
fn_info_array = build_index_type (size_int (n_funcs));
|
||||
fn_info_array = build_array_type (fn_info_type, fn_info_array);
|
||||
field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
|
||||
fn_info_array);
|
||||
DECL_CHAIN (field) = fields;
|
||||
fields = field;
|
||||
|
||||
finish_builtin_struct (type, "__gcov_info", fields, NULL_TREE);
|
||||
}
|
||||
|
||||
/* Creates the gcov_info initializer. Returns a CONSTRUCTOR. */
|
||||
|
||||
static tree
|
||||
build_info (tree info_type, tree fn_type, tree key_var, unsigned n_funcs)
|
||||
{
|
||||
tree info_fields = TYPE_FIELDS (info_type);
|
||||
tree merge_fn_type, fn_info_ptr_type;
|
||||
unsigned ix;
|
||||
tree filename_string;
|
||||
int da_file_name_len;
|
||||
const struct function_list *fn;
|
||||
VEC(constructor_elt,gc) *v1 = NULL;
|
||||
VEC(constructor_elt,gc) *v2 = NULL;
|
||||
VEC(constructor_elt,gc) *v3 = NULL;
|
||||
|
||||
/* Version ident */
|
||||
CONSTRUCTOR_APPEND_ELT (v1, info_fields,
|
||||
build_int_cstu (TREE_TYPE (info_fields),
|
||||
GCOV_VERSION));
|
||||
info_fields = DECL_CHAIN (info_fields);
|
||||
|
||||
/* next -- NULL */
|
||||
CONSTRUCTOR_APPEND_ELT (v1, info_fields, null_pointer_node);
|
||||
info_fields = DECL_CHAIN (info_fields);
|
||||
|
||||
/* stamp */
|
||||
CONSTRUCTOR_APPEND_ELT (v1, info_fields,
|
||||
build_int_cstu (TREE_TYPE (info_fields),
|
||||
local_tick));
|
||||
info_fields = DECL_CHAIN (info_fields);
|
||||
|
||||
/* Filename */
|
||||
da_file_name_len = strlen (da_file_name);
|
||||
filename_string = build_string (da_file_name_len + 1, da_file_name);
|
||||
TREE_TYPE (filename_string) = build_array_type
|
||||
(char_type_node, build_index_type (size_int (da_file_name_len)));
|
||||
CONSTRUCTOR_APPEND_ELT (v1, field,
|
||||
build1 (ADDR_EXPR, string_type, filename_string));
|
||||
CONSTRUCTOR_APPEND_ELT (v1, info_fields,
|
||||
build1 (ADDR_EXPR, TREE_TYPE (info_fields),
|
||||
filename_string));
|
||||
info_fields = DECL_CHAIN (info_fields);
|
||||
|
||||
/* Build the fn_info type and initializer. */
|
||||
fn_info_type = build_fn_info_type (n_ctr_types);
|
||||
fn_info_ptr_type = build_pointer_type (build_qualified_type
|
||||
(fn_info_type, TYPE_QUAL_CONST));
|
||||
for (fn = functions_head, n_fns = 0; fn; fn = fn->next, n_fns++)
|
||||
CONSTRUCTOR_APPEND_ELT (v2, NULL_TREE,
|
||||
build_fn_info_value (fn, fn_info_type));
|
||||
|
||||
if (n_fns)
|
||||
{
|
||||
tree array_type;
|
||||
|
||||
array_type = build_index_type (size_int (n_fns - 1));
|
||||
array_type = build_array_type (fn_info_type, array_type);
|
||||
|
||||
fn_info_value = build_constructor (array_type, v2);
|
||||
fn_info_value = build1 (ADDR_EXPR, fn_info_ptr_type, fn_info_value);
|
||||
}
|
||||
else
|
||||
fn_info_value = null_pointer_node;
|
||||
|
||||
/* number of functions */
|
||||
field = build_decl (BUILTINS_LOCATION,
|
||||
FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ());
|
||||
DECL_CHAIN (field) = fields;
|
||||
fields = field;
|
||||
CONSTRUCTOR_APPEND_ELT (v1, field,
|
||||
build_int_cstu (get_gcov_unsigned_t (), n_fns));
|
||||
|
||||
/* fn_info table */
|
||||
field = build_decl (BUILTINS_LOCATION,
|
||||
FIELD_DECL, NULL_TREE, fn_info_ptr_type);
|
||||
DECL_CHAIN (field) = fields;
|
||||
fields = field;
|
||||
CONSTRUCTOR_APPEND_ELT (v1, field, fn_info_value);
|
||||
|
||||
/* counter_mask */
|
||||
field = build_decl (BUILTINS_LOCATION,
|
||||
FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ());
|
||||
DECL_CHAIN (field) = fields;
|
||||
fields = field;
|
||||
CONSTRUCTOR_APPEND_ELT (v1, field,
|
||||
build_int_cstu (get_gcov_unsigned_t (),
|
||||
prg_ctr_mask));
|
||||
|
||||
/* counters */
|
||||
ctr_info_type = build_ctr_info_type ();
|
||||
ctr_info_ary_type = build_index_type (size_int (n_ctr_types));
|
||||
ctr_info_ary_type = build_array_type (ctr_info_type, ctr_info_ary_type);
|
||||
v2 = NULL;
|
||||
/* merge fn array -- NULL slots indicate unmeasured counters */
|
||||
merge_fn_type = TREE_TYPE (TREE_TYPE (info_fields));
|
||||
for (ix = 0; ix != GCOV_COUNTERS; ix++)
|
||||
if (prg_ctr_mask & (1 << ix))
|
||||
CONSTRUCTOR_APPEND_ELT (v2, NULL_TREE,
|
||||
build_ctr_info_value (ix, ctr_info_type));
|
||||
ctr_info_value = build_constructor (ctr_info_ary_type, v2);
|
||||
{
|
||||
tree ptr = null_pointer_node;
|
||||
|
||||
field = build_decl (BUILTINS_LOCATION,
|
||||
FIELD_DECL, NULL_TREE, ctr_info_ary_type);
|
||||
DECL_CHAIN (field) = fields;
|
||||
fields = field;
|
||||
CONSTRUCTOR_APPEND_ELT (v1, field, ctr_info_value);
|
||||
if ((1u << ix) & prg_ctr_mask)
|
||||
{
|
||||
tree merge_fn = build_decl (BUILTINS_LOCATION,
|
||||
FUNCTION_DECL,
|
||||
get_identifier (ctr_merge_functions[ix]),
|
||||
TREE_TYPE (merge_fn_type));
|
||||
DECL_EXTERNAL (merge_fn) = 1;
|
||||
TREE_PUBLIC (merge_fn) = 1;
|
||||
DECL_ARTIFICIAL (merge_fn) = 1;
|
||||
TREE_NOTHROW (merge_fn) = 1;
|
||||
/* Initialize assembler name so we can stream out. */
|
||||
DECL_ASSEMBLER_NAME (merge_fn);
|
||||
ptr = build1 (ADDR_EXPR, merge_fn_type, merge_fn);
|
||||
}
|
||||
CONSTRUCTOR_APPEND_ELT (v2, NULL, ptr);
|
||||
}
|
||||
CONSTRUCTOR_APPEND_ELT (v1, info_fields,
|
||||
build_constructor (TREE_TYPE (info_fields), v2));
|
||||
info_fields = DECL_CHAIN (info_fields);
|
||||
|
||||
finish_builtin_struct (type, "__gcov_info", fields, NULL_TREE);
|
||||
/* n_functions */
|
||||
CONSTRUCTOR_APPEND_ELT (v1, info_fields,
|
||||
build_int_cstu (TREE_TYPE (info_fields), n_funcs));
|
||||
info_fields = DECL_CHAIN (info_fields);
|
||||
|
||||
/* Build the fn_info type and initializer. */
|
||||
fn_info_ptr_type = TREE_TYPE (TREE_TYPE (info_fields));
|
||||
|
||||
for (fn = functions_head; fn; fn = fn->next)
|
||||
{
|
||||
tree init = build_fn_info (fn, fn_type, key_var);
|
||||
tree var = build_var (fn->fn_decl, fn_type, -1);
|
||||
|
||||
return build_constructor (type, v1);
|
||||
DECL_INITIAL (var) = init;
|
||||
varpool_finalize_decl (var);
|
||||
|
||||
CONSTRUCTOR_APPEND_ELT (v3, NULL,
|
||||
build1 (ADDR_EXPR, fn_info_ptr_type, var));
|
||||
}
|
||||
CONSTRUCTOR_APPEND_ELT (v1, info_fields,
|
||||
build_constructor (TREE_TYPE (info_fields), v3));
|
||||
return build_constructor (info_type, v1);
|
||||
}
|
||||
|
||||
/* Write out the structure which libgcov uses to locate all the
|
||||
@ -982,6 +989,11 @@ static void
|
||||
create_coverage (void)
|
||||
{
|
||||
tree gcov_info, gcov_init, body, t;
|
||||
tree gcov_info_type, gcov_fn_type;
|
||||
unsigned n_counters = 0, n_functions = 0;
|
||||
struct function_list *fn;
|
||||
struct function_list **fn_prev;
|
||||
unsigned ix;
|
||||
char name_buf[32];
|
||||
|
||||
no_coverage = 1; /* Disable any further coverage. */
|
||||
@ -989,14 +1001,37 @@ create_coverage (void)
|
||||
if (!prg_ctr_mask)
|
||||
return;
|
||||
|
||||
t = build_gcov_info ();
|
||||
if (cgraph_dump_file)
|
||||
fprintf (cgraph_dump_file, "Using data file %s\n", da_file_name);
|
||||
|
||||
for (ix = 0; ix != GCOV_COUNTERS; ix++)
|
||||
if ((1u << ix) & prg_ctr_mask)
|
||||
n_counters++;
|
||||
for (fn_prev = &functions_head; (fn = *fn_prev);)
|
||||
if (DECL_STRUCT_FUNCTION (fn->fn_decl))
|
||||
{
|
||||
n_functions++;
|
||||
fn_prev = &fn->next;
|
||||
}
|
||||
else
|
||||
/* The function is not being emitted, remove from list. */
|
||||
*fn_prev = fn->next;
|
||||
|
||||
/* Build the info and fn_info types. These are mutually recursive. */
|
||||
gcov_info_type = lang_hooks.types.make_type (RECORD_TYPE);
|
||||
gcov_fn_type = lang_hooks.types.make_type (RECORD_TYPE);
|
||||
build_fn_info_type (gcov_fn_type, n_counters, gcov_info_type);
|
||||
build_info_type (gcov_info_type, n_functions, gcov_fn_type);
|
||||
|
||||
/* Build the gcov info var, this is referred to in its own
|
||||
initializer. */
|
||||
gcov_info = build_decl (BUILTINS_LOCATION,
|
||||
VAR_DECL, NULL_TREE, TREE_TYPE (t));
|
||||
VAR_DECL, NULL_TREE, gcov_info_type);
|
||||
TREE_STATIC (gcov_info) = 1;
|
||||
ASM_GENERATE_INTERNAL_LABEL (name_buf, "LPBX", 0);
|
||||
DECL_NAME (gcov_info) = get_identifier (name_buf);
|
||||
DECL_INITIAL (gcov_info) = t;
|
||||
DECL_INITIAL (gcov_info) = build_info (gcov_info_type, gcov_fn_type,
|
||||
gcov_info, n_functions);
|
||||
|
||||
/* Build structure. */
|
||||
varpool_finalize_decl (gcov_info);
|
||||
|
@ -276,23 +276,28 @@ dump_file (const char *filename)
|
||||
|
||||
static void
|
||||
tag_function (const char *filename ATTRIBUTE_UNUSED,
|
||||
unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED)
|
||||
unsigned tag ATTRIBUTE_UNUSED, unsigned length)
|
||||
{
|
||||
unsigned long pos = gcov_position ();
|
||||
|
||||
printf (" ident=%u", 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)
|
||||
if (!length)
|
||||
printf (" placeholder");
|
||||
else
|
||||
{
|
||||
const char *name;
|
||||
printf (" ident=%u", gcov_read_unsigned ());
|
||||
printf (", lineno_checksum=0x%08x", gcov_read_unsigned ());
|
||||
printf (", cfg_checksum_checksum=0x%08x", gcov_read_unsigned ());
|
||||
|
||||
name = gcov_read_string ();
|
||||
printf (", `%s'", name ? name : "NULL");
|
||||
name = gcov_read_string ();
|
||||
printf (" %s", name ? name : "NULL");
|
||||
printf (":%u", gcov_read_unsigned ());
|
||||
if (gcov_position () - pos < length)
|
||||
{
|
||||
const char *name;
|
||||
|
||||
name = gcov_read_string ();
|
||||
printf (", `%s'", name ? name : "NULL");
|
||||
name = gcov_read_string ();
|
||||
printf (" %s", name ? name : "NULL");
|
||||
printf (":%u", gcov_read_unsigned ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -130,26 +130,26 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
blocks they are for.
|
||||
|
||||
The data file contains the following records.
|
||||
data: {unit function-data* summary:object summary:program*}*
|
||||
data: {unit summary:object summary:program* function-data*}*
|
||||
unit: header int32:checksum
|
||||
function-data: announce_function arc_counts
|
||||
function-data: announce_function present counts
|
||||
announce_function: header int32:ident
|
||||
int32:lineno_checksum int32:cfg_checksum
|
||||
arc_counts: header int64:count*
|
||||
summary: int32:checksum {count-summary}GCOV_COUNTERS
|
||||
present: header int32:present
|
||||
counts: header int64:count*
|
||||
summary: int32:checksum {count-summary}GCOV_COUNTERS_SUMMABLE
|
||||
count-summary: int32:num int32:runs int64:sum
|
||||
int64:max int64:sum_max
|
||||
|
||||
The ANNOUNCE_FUNCTION record is the same as that in the note file,
|
||||
but without the source location. The ARC_COUNTS gives the counter
|
||||
values for those arcs that are instrumented. The SUMMARY records
|
||||
give information about the whole object file and about the whole
|
||||
but without the source location. The COUNTS gives the
|
||||
counter values for instrumented features. The about the whole
|
||||
program. The checksum is used for whole program summaries, and
|
||||
disambiguates different programs which include the same
|
||||
instrumented object file. There may be several program summaries,
|
||||
each with a unique checksum. The object summary's checksum is zero.
|
||||
Note that the data file might contain information from several runs
|
||||
concatenated, or the data might be merged.
|
||||
each with a unique checksum. The object summary's checksum is
|
||||
zero. Note that the data file might contain information from
|
||||
several runs concatenated, or the data might be merged.
|
||||
|
||||
This file is included by both the compiler, gcov tools and the
|
||||
runtime support library libgcov. IN_LIBGCOV and IN_GCOV are used to
|
||||
@ -307,7 +307,7 @@ typedef HOST_WIDEST_INT gcov_type;
|
||||
#define GCOV_TAG_COUNTER_BASE ((gcov_unsigned_t)0x01a10000)
|
||||
#define GCOV_TAG_COUNTER_LENGTH(NUM) ((NUM) * 2)
|
||||
#define GCOV_TAG_COUNTER_NUM(LENGTH) ((LENGTH) / 2)
|
||||
#define GCOV_TAG_OBJECT_SUMMARY ((gcov_unsigned_t)0xa1000000)
|
||||
#define GCOV_TAG_OBJECT_SUMMARY ((gcov_unsigned_t)0xa1000000) /* Obsolete */
|
||||
#define GCOV_TAG_PROGRAM_SUMMARY ((gcov_unsigned_t)0xa3000000)
|
||||
#define GCOV_TAG_SUMMARY_LENGTH \
|
||||
(1 + GCOV_COUNTERS_SUMMABLE * (2 + 3 * 2))
|
||||
@ -343,7 +343,7 @@ typedef HOST_WIDEST_INT gcov_type;
|
||||
|
||||
/* A list of human readable names of the counters */
|
||||
#define GCOV_COUNTER_NAMES {"arcs", "interval", "pow2", "single", \
|
||||
"delta","indirect_call", "average", "ior"}
|
||||
"delta", "indirect_call", "average", "ior"}
|
||||
|
||||
/* Names of merge functions for counters. */
|
||||
#define GCOV_MERGE_FUNCTIONS {"__gcov_merge_add", \
|
||||
@ -410,30 +410,31 @@ struct gcov_summary
|
||||
by write_profile must match these. */
|
||||
|
||||
#if IN_LIBGCOV
|
||||
/* Information about a single function. This uses the trailing array
|
||||
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 lineno_checksum; /* function lineo_checksum */
|
||||
gcov_unsigned_t cfg_checksum; /* function cfg checksum */
|
||||
unsigned n_ctrs[0]; /* instrumented counters */
|
||||
};
|
||||
|
||||
/* Type of function used to merge counters. */
|
||||
typedef void (*gcov_merge_fn) (gcov_type *, gcov_unsigned_t);
|
||||
|
||||
/* Information about counters. */
|
||||
/* Information about counters for a single function. */
|
||||
struct gcov_ctr_info
|
||||
{
|
||||
gcov_unsigned_t num; /* number of counters. */
|
||||
gcov_type *values; /* their values. */
|
||||
gcov_merge_fn merge; /* The function used to merge them. */
|
||||
};
|
||||
|
||||
/* Information about a single function. This uses the trailing array
|
||||
idiom. The number of counters is determined from the merge pointer
|
||||
array in gcov_info. The key is used to detect which of a set of
|
||||
comdat functions was selected -- it points to the gcov_info object
|
||||
of the object file containing the selected comdat function. */
|
||||
|
||||
struct gcov_fn_info
|
||||
{
|
||||
const struct gcov_info *key; /* comdat key */
|
||||
gcov_unsigned_t ident; /* unique ident of function */
|
||||
gcov_unsigned_t lineno_checksum; /* function lineo_checksum */
|
||||
gcov_unsigned_t cfg_checksum; /* function cfg checksum */
|
||||
struct gcov_ctr_info ctrs[0]; /* instrumented counters */
|
||||
};
|
||||
|
||||
/* Type of function used to merge counters. */
|
||||
typedef void (*gcov_merge_fn) (gcov_type *, gcov_unsigned_t);
|
||||
|
||||
/* Information about a single object file. */
|
||||
struct gcov_info
|
||||
{
|
||||
@ -443,14 +444,12 @@ struct gcov_info
|
||||
gcov_unsigned_t stamp; /* uniquifying time stamp */
|
||||
const char *filename; /* output file name */
|
||||
|
||||
gcov_merge_fn merge[GCOV_COUNTERS]; /* merge functions (null for
|
||||
unused) */
|
||||
|
||||
unsigned n_functions; /* number of functions */
|
||||
const struct gcov_fn_info *functions; /* table of functions */
|
||||
|
||||
unsigned ctr_mask; /* mask of counters instrumented. */
|
||||
struct gcov_ctr_info counts[0]; /* count data. The number of bits
|
||||
set in the ctr_mask field
|
||||
determines how big this array
|
||||
is. */
|
||||
const struct gcov_fn_info *functions[0]; /* pointers to function
|
||||
information */
|
||||
};
|
||||
|
||||
/* Register a new object file module. */
|
||||
|
126
gcc/gcov.c
126
gcc/gcov.c
@ -265,7 +265,7 @@ static unsigned source_index;
|
||||
|
||||
/* This holds data summary information. */
|
||||
|
||||
static struct gcov_summary object_summary;
|
||||
static unsigned object_runs;
|
||||
static unsigned program_count;
|
||||
|
||||
/* Modification time of graph file. */
|
||||
@ -362,6 +362,7 @@ static int output_branch_count (FILE *, int, const arc_t *);
|
||||
static void output_lines (FILE *, const source_t *);
|
||||
static char *make_gcov_file_name (const char *, const char *);
|
||||
static void release_structures (void);
|
||||
static void release_function (function_t *);
|
||||
extern int main (int, char **);
|
||||
|
||||
int
|
||||
@ -537,7 +538,7 @@ static void
|
||||
process_file (const char *file_name)
|
||||
{
|
||||
function_t *fn;
|
||||
function_t *fn_p;
|
||||
function_t **fn_p;
|
||||
function_t *old_functions;
|
||||
|
||||
/* Save and clear the list of current functions. They will be appended
|
||||
@ -558,11 +559,25 @@ process_file (const char *file_name)
|
||||
if (read_count_file ())
|
||||
return;
|
||||
|
||||
for (fn_p = NULL, fn = functions; fn; fn_p = fn, fn = fn->next)
|
||||
solve_flow_graph (fn);
|
||||
fn_p = &functions;
|
||||
while ((fn = *fn_p) != NULL)
|
||||
{
|
||||
if (fn->counts)
|
||||
{
|
||||
solve_flow_graph (fn);
|
||||
fn_p = &fn->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The function was not in the executable -- some other
|
||||
instance must have been selected. */
|
||||
function_t *next = fn->next;
|
||||
release_function (fn);
|
||||
*fn_p = next;
|
||||
}
|
||||
}
|
||||
|
||||
if (fn_p)
|
||||
fn_p->next = old_functions;
|
||||
*fn_p = old_functions;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -591,7 +606,7 @@ generate_results (const char *file_name)
|
||||
{
|
||||
accumulate_line_counts (src);
|
||||
function_summary (&src->coverage, "File");
|
||||
if (flag_gcov_file)
|
||||
if (flag_gcov_file && src->coverage.lines)
|
||||
{
|
||||
char *gcov_file_name = make_gcov_file_name (file_name, src->name);
|
||||
FILE *gcov_file = fopen (gcov_file_name, "w");
|
||||
@ -615,6 +630,28 @@ generate_results (const char *file_name)
|
||||
}
|
||||
}
|
||||
|
||||
/* Release a function structure */
|
||||
|
||||
static void
|
||||
release_function (function_t *fn)
|
||||
{
|
||||
unsigned ix;
|
||||
block_t *block;
|
||||
|
||||
for (ix = fn->num_blocks, block = fn->blocks; ix--; block++)
|
||||
{
|
||||
arc_t *arc, *arc_n;
|
||||
|
||||
for (arc = block->succ; arc; arc = arc_n)
|
||||
{
|
||||
arc_n = arc->succ_next;
|
||||
free (arc);
|
||||
}
|
||||
}
|
||||
free (fn->blocks);
|
||||
free (fn->counts);
|
||||
}
|
||||
|
||||
/* Release all memory used. */
|
||||
|
||||
static void
|
||||
@ -633,22 +670,8 @@ release_structures (void)
|
||||
|
||||
while ((fn = functions))
|
||||
{
|
||||
unsigned ix;
|
||||
block_t *block;
|
||||
|
||||
functions = fn->next;
|
||||
for (ix = fn->num_blocks, block = fn->blocks; ix--; block++)
|
||||
{
|
||||
arc_t *arc, *arc_n;
|
||||
|
||||
for (arc = block->succ; arc; arc = arc_n)
|
||||
{
|
||||
arc_n = arc->succ_next;
|
||||
free (arc);
|
||||
}
|
||||
}
|
||||
free (fn->blocks);
|
||||
free (fn->counts);
|
||||
release_function (fn);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1085,35 +1108,39 @@ read_count_file (void)
|
||||
unsigned length = gcov_read_unsigned ();
|
||||
unsigned long base = gcov_position ();
|
||||
|
||||
if (tag == GCOV_TAG_OBJECT_SUMMARY)
|
||||
gcov_read_summary (&object_summary);
|
||||
else if (tag == GCOV_TAG_PROGRAM_SUMMARY)
|
||||
program_count++;
|
||||
else if (tag == GCOV_TAG_FUNCTION)
|
||||
if (tag == GCOV_TAG_PROGRAM_SUMMARY)
|
||||
{
|
||||
{
|
||||
unsigned ident = gcov_read_unsigned ();
|
||||
struct function_info *fn_n = functions;
|
||||
struct gcov_summary summary;
|
||||
gcov_read_summary (&summary);
|
||||
object_runs += summary.ctrs[GCOV_COUNTER_ARCS].runs;
|
||||
program_count++;
|
||||
}
|
||||
else if (tag == GCOV_TAG_FUNCTION && !length)
|
||||
; /* placeholder */
|
||||
else if (tag == GCOV_TAG_FUNCTION && length == GCOV_TAG_FUNCTION_LENGTH)
|
||||
{
|
||||
unsigned ident;
|
||||
struct function_info *fn_n;
|
||||
|
||||
/* Try to find the function in the list.
|
||||
To speed up the search, first start from the last function
|
||||
found. */
|
||||
for (fn = fn ? fn->next : NULL; ; fn = fn->next)
|
||||
{
|
||||
if (fn)
|
||||
;
|
||||
else if ((fn = fn_n))
|
||||
fn_n = NULL;
|
||||
else
|
||||
{
|
||||
fnotice (stderr, "%s:unknown function '%u'\n",
|
||||
da_file_name, ident);
|
||||
break;
|
||||
}
|
||||
if (fn->ident == ident)
|
||||
/* Try to find the function in the list. To speed up the
|
||||
search, first start from the last function found. */
|
||||
ident = gcov_read_unsigned ();
|
||||
fn_n = functions;
|
||||
for (fn = fn ? fn->next : NULL; ; fn = fn->next)
|
||||
{
|
||||
if (fn)
|
||||
;
|
||||
else if ((fn = fn_n))
|
||||
fn_n = NULL;
|
||||
else
|
||||
{
|
||||
fnotice (stderr, "%s:unknown function '%u'\n",
|
||||
da_file_name, ident);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fn->ident == ident)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!fn)
|
||||
;
|
||||
@ -1908,8 +1935,7 @@ output_lines (FILE *gcov_file, const source_t *src)
|
||||
fprintf (gcov_file, "%9s:%5d:Graph:%s\n", "-", 0, bbg_file_name);
|
||||
fprintf (gcov_file, "%9s:%5d:Data:%s\n", "-", 0,
|
||||
no_data_file ? "-" : da_file_name);
|
||||
fprintf (gcov_file, "%9s:%5d:Runs:%u\n", "-", 0,
|
||||
object_summary.ctrs[GCOV_COUNTER_ARCS].runs);
|
||||
fprintf (gcov_file, "%9s:%5d:Runs:%u\n", "-", 0, object_runs);
|
||||
}
|
||||
fprintf (gcov_file, "%9s:%5d:Programs:%u\n", "-", 0, program_count);
|
||||
|
||||
|
@ -1,3 +1,14 @@
|
||||
2011-11-07 Nathan Sidwell <nathan@acm.org>
|
||||
|
||||
* gcc.dg/profile-dir-1.c: Adjust final scan.
|
||||
* gcc.dg/profile-dir-2.c: Adjust final scan.
|
||||
* gcc.dg/profile-dir-3.c: Adjust final scan.
|
||||
* gcc.misc-tests/gcov.exp: Adjust regexp.
|
||||
* gcc.misc-tests/gcov-12.c: New.
|
||||
* gcc.misc-tests/gcov-13.c: New.
|
||||
* gcc.misc-tests/gcovpart-13b.c: New.
|
||||
* gcc.misc-tests/gcov-14.c: New.
|
||||
|
||||
2011-11-07 Jason Merrill <jason@redhat.com>
|
||||
|
||||
PR c++/35688
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O -fprofile-generate=. -fdump-ipa-profile" } */
|
||||
/* { dg-final { scan-ipa-dump " ./profile-dir-1.gcda" "profile" } } */
|
||||
/* { dg-options "-O -fprofile-generate=. -fdump-ipa-cgraph" } */
|
||||
/* { dg-final { scan-ipa-dump " ./profile-dir-1.gcda" "cgraph" } } */
|
||||
|
||||
int
|
||||
main(void)
|
||||
@ -8,4 +8,4 @@ main(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { cleanup-ipa-dump "profile" } } */
|
||||
/* { dg-final { cleanup-ipa-dump "cgraph" } } */
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O -fprofile-generate -fdump-ipa-profile" } */
|
||||
/* { dg-final { scan-ipa-dump "/profile-dir-2.gcda" "profile" } } */
|
||||
/* { dg-options "-O -fprofile-generate -fdump-ipa-cgraph" } */
|
||||
/* { dg-final { scan-ipa-dump "/profile-dir-2.gcda" "cgraph" } } */
|
||||
|
||||
int
|
||||
main(void)
|
||||
@ -8,4 +8,4 @@ main(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { cleanup-ipa-dump "profile" } } */
|
||||
/* { dg-final { cleanup-ipa-dump "cgraph" } } */
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O -fprofile-generate -fprofile-dir=. -fdump-ipa-profile" } */
|
||||
/* { dg-final { scan-ipa-dump " ./profile-dir-3.gcda" "profile" } } */
|
||||
/* { dg-options "-O -fprofile-generate -fprofile-dir=. -fdump-ipa-cgraph" } */
|
||||
/* { dg-final { scan-ipa-dump " ./profile-dir-3.gcda" "cgraph" } } */
|
||||
|
||||
int
|
||||
main(void)
|
||||
@ -8,4 +8,4 @@ main(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { cleanup-ipa-dump "profile" } } */
|
||||
/* { dg-final { cleanup-ipa-dump "cgraph" } } */
|
||||
|
17
gcc/testsuite/gcc.misc-tests/gcov-12.c
Normal file
17
gcc/testsuite/gcc.misc-tests/gcov-12.c
Normal file
@ -0,0 +1,17 @@
|
||||
/* Test gcov weak ellision. */
|
||||
|
||||
/* { dg-options "-fprofile-arcs -ftest-coverage" } */
|
||||
/* { dg-require-weak "" } */
|
||||
/* { dg-do run { target native } } */
|
||||
|
||||
int __attribute__ ((weak)) weak ()
|
||||
{
|
||||
return 0; /* count(1) */
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
return weak (); /* count(1) */
|
||||
}
|
||||
|
||||
/* { dg-final { run-gcov { -a gcov-12.c } } } */
|
18
gcc/testsuite/gcc.misc-tests/gcov-13.c
Normal file
18
gcc/testsuite/gcc.misc-tests/gcov-13.c
Normal file
@ -0,0 +1,18 @@
|
||||
/* Test gcov weak ellision. */
|
||||
|
||||
/* { dg-options "-fprofile-arcs -ftest-coverage" } */
|
||||
/* { dg-require-weak "" } */
|
||||
/* { dg-do run { target native } } */
|
||||
/* { dg-additional-sources "gcovpart-13b.c" } */
|
||||
|
||||
int __attribute__ ((weak)) weak ()
|
||||
{
|
||||
return 1; /* count(-) */
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
return weak (); /* count(1) */
|
||||
}
|
||||
|
||||
/* { dg-final { run-gcov { -a gcov-13.c } } } */
|
24
gcc/testsuite/gcc.misc-tests/gcov-14.c
Normal file
24
gcc/testsuite/gcc.misc-tests/gcov-14.c
Normal file
@ -0,0 +1,24 @@
|
||||
/* Test gcov extern inline. */
|
||||
|
||||
/* { dg-options "-O2 -fprofile-arcs -ftest-coverage" } */
|
||||
/* { dg-require-weak "" } */
|
||||
/* { dg-do run { target native } } */
|
||||
|
||||
extern int __attribute__ ((weak)) Foo ();
|
||||
|
||||
extern __inline int Foo ()
|
||||
{
|
||||
return 0; /* count(-) */
|
||||
}
|
||||
|
||||
int (* __attribute__ ((noinline)) Bar ()) ()
|
||||
{
|
||||
return Foo; /* count(1) */
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
return Bar () != 0; /* count(1) */
|
||||
}
|
||||
|
||||
/* { dg-final { run-gcov { -a gcov-14.c } } } */
|
@ -33,7 +33,7 @@ if { ![is_remote host] && [string match "*/*" [lindex $GCC_UNDER_TEST 0]] } {
|
||||
dg-init
|
||||
|
||||
# Delete old .gcda files.
|
||||
set files [glob -nocomplain gcov-*.gcda]
|
||||
set files [glob -nocomplain gcov*.gcda]
|
||||
if { $files != "" } {
|
||||
eval "remote_file build delete $files"
|
||||
}
|
||||
|
4
gcc/testsuite/gcc.misc-tests/gcovpart-13b.c
Normal file
4
gcc/testsuite/gcc.misc-tests/gcovpart-13b.c
Normal file
@ -0,0 +1,4 @@
|
||||
int weak ()
|
||||
{
|
||||
return 0; /* count(1) */
|
||||
}
|
@ -1,3 +1,9 @@
|
||||
2011-11-07 Nathan Sidwell <nathan@acm.org>
|
||||
|
||||
* libgcov.c (struct gcov_fn_buffer): New struct.
|
||||
(buffer_fn_data): New helper.
|
||||
(gcov_exit): Rework for new gcov data structures.
|
||||
|
||||
2011-11-07 Georg-Johann Lay <avr@gjlay.de>
|
||||
|
||||
PR target/49313
|
||||
|
437
libgcc/libgcov.c
437
libgcc/libgcov.c
@ -78,6 +78,14 @@ void __gcov_merge_delta (gcov_type *counters __attribute__ ((unused)),
|
||||
#ifdef L_gcov
|
||||
#include "gcov-io.c"
|
||||
|
||||
struct gcov_fn_buffer
|
||||
{
|
||||
struct gcov_fn_buffer *next;
|
||||
unsigned fn_ix;
|
||||
struct gcov_fn_info info;
|
||||
/* note gcov_fn_info ends in a trailing array. */
|
||||
};
|
||||
|
||||
/* Chain of per-object gcov structures. */
|
||||
static struct gcov_info *gcov_list;
|
||||
|
||||
@ -135,6 +143,64 @@ create_file_directory (char *filename)
|
||||
#endif
|
||||
}
|
||||
|
||||
static struct gcov_fn_buffer **
|
||||
buffer_fn_data (struct gcov_info *gi_ptr, struct gcov_fn_buffer **end_ptr,
|
||||
unsigned fn_ix)
|
||||
{
|
||||
unsigned n_ctrs = 0, ix;
|
||||
struct gcov_fn_buffer *fn_buffer;
|
||||
|
||||
for (ix = GCOV_COUNTERS; ix--;)
|
||||
if (gi_ptr->merge[ix])
|
||||
n_ctrs++;
|
||||
|
||||
fn_buffer = (struct gcov_fn_buffer *)malloc
|
||||
(sizeof (*fn_buffer) + sizeof (fn_buffer->info.ctrs[0]) * n_ctrs);
|
||||
|
||||
if (!fn_buffer)
|
||||
return 0; /* We'll horribly fail. */
|
||||
|
||||
fn_buffer->next = 0;
|
||||
fn_buffer->fn_ix = fn_ix;
|
||||
fn_buffer->info.ident = gcov_read_unsigned ();
|
||||
fn_buffer->info.lineno_checksum = gcov_read_unsigned ();
|
||||
fn_buffer->info.cfg_checksum = gcov_read_unsigned ();
|
||||
|
||||
for (n_ctrs = ix = 0; ix != GCOV_COUNTERS; ix++)
|
||||
{
|
||||
gcov_unsigned_t length;
|
||||
gcov_type *values;
|
||||
|
||||
if (!gi_ptr->merge[ix])
|
||||
continue;
|
||||
|
||||
if (gcov_read_unsigned () != GCOV_TAG_FOR_COUNTER (ix))
|
||||
goto fail;
|
||||
|
||||
length = GCOV_TAG_COUNTER_NUM (gcov_read_unsigned ());
|
||||
values = (gcov_type *)malloc (length * sizeof (gcov_type));
|
||||
if (!values)
|
||||
{
|
||||
while (n_ctrs--)
|
||||
free (fn_buffer->info.ctrs[n_ctrs].values);
|
||||
goto fail;
|
||||
}
|
||||
fn_buffer->info.ctrs[n_ctrs].num = length;
|
||||
fn_buffer->info.ctrs[n_ctrs].values = values;
|
||||
|
||||
while (length--)
|
||||
*values++ = gcov_read_counter ();
|
||||
n_ctrs++;
|
||||
}
|
||||
|
||||
*end_ptr = fn_buffer;
|
||||
return &fn_buffer->next;
|
||||
|
||||
fail:
|
||||
free (fn_buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check if VERSION of the info block PTR matches libgcov one.
|
||||
Return 1 on success, or zero in case of versions mismatch.
|
||||
If FILENAME is not NULL, its value used for reporting purposes
|
||||
@ -170,39 +236,46 @@ static void
|
||||
gcov_exit (void)
|
||||
{
|
||||
struct gcov_info *gi_ptr;
|
||||
struct gcov_summary this_program;
|
||||
struct gcov_summary all;
|
||||
const struct gcov_fn_info *gfi_ptr;
|
||||
struct gcov_summary this_prg; /* summary for program. */
|
||||
struct gcov_summary all_prg; /* summary for all instances of program. */
|
||||
struct gcov_ctr_summary *cs_ptr;
|
||||
const struct gcov_ctr_info *ci_ptr;
|
||||
unsigned t_ix;
|
||||
unsigned t_ix, f_ix;
|
||||
gcov_unsigned_t c_num;
|
||||
const char *gcov_prefix;
|
||||
int gcov_prefix_strip = 0;
|
||||
size_t prefix_length;
|
||||
char *gi_filename, *gi_filename_up;
|
||||
|
||||
memset (&all, 0, sizeof (all));
|
||||
memset (&all_prg, 0, sizeof (all_prg));
|
||||
/* Find the totals for this execution. */
|
||||
memset (&this_program, 0, sizeof (this_program));
|
||||
memset (&this_prg, 0, sizeof (this_prg));
|
||||
for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
|
||||
{
|
||||
ci_ptr = gi_ptr->counts;
|
||||
for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
|
||||
{
|
||||
if (!((1 << t_ix) & gi_ptr->ctr_mask))
|
||||
continue;
|
||||
for (f_ix = 0; f_ix != gi_ptr->n_functions; f_ix++)
|
||||
{
|
||||
gfi_ptr = gi_ptr->functions[f_ix];
|
||||
|
||||
if (!gfi_ptr || gfi_ptr->key != gi_ptr)
|
||||
continue;
|
||||
|
||||
ci_ptr = gfi_ptr->ctrs;
|
||||
for (t_ix = 0; t_ix != GCOV_COUNTERS_SUMMABLE; t_ix++)
|
||||
{
|
||||
if (!gi_ptr->merge[t_ix])
|
||||
continue;
|
||||
|
||||
cs_ptr = &this_program.ctrs[t_ix];
|
||||
cs_ptr->num += ci_ptr->num;
|
||||
for (c_num = 0; c_num < ci_ptr->num; c_num++)
|
||||
{
|
||||
cs_ptr->sum_all += ci_ptr->values[c_num];
|
||||
if (cs_ptr->run_max < ci_ptr->values[c_num])
|
||||
cs_ptr->run_max = ci_ptr->values[c_num];
|
||||
}
|
||||
ci_ptr++;
|
||||
}
|
||||
}
|
||||
cs_ptr = &this_prg.ctrs[t_ix];
|
||||
cs_ptr->num += ci_ptr->num;
|
||||
for (c_num = 0; c_num < ci_ptr->num; c_num++)
|
||||
{
|
||||
cs_ptr->sum_all += ci_ptr->values[c_num];
|
||||
if (cs_ptr->run_max < ci_ptr->values[c_num])
|
||||
cs_ptr->run_max = ci_ptr->values[c_num];
|
||||
}
|
||||
ci_ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
/* Check if the level of dirs to strip off specified. */
|
||||
@ -215,6 +288,7 @@ gcov_exit (void)
|
||||
gcov_prefix_strip = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get file name relocation prefix. Non-absolute values are ignored. */
|
||||
gcov_prefix = getenv("GCOV_PREFIX");
|
||||
if (gcov_prefix)
|
||||
@ -244,24 +318,20 @@ gcov_exit (void)
|
||||
/* Now merge each file. */
|
||||
for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
|
||||
{
|
||||
struct gcov_summary this_object;
|
||||
struct gcov_summary object, program;
|
||||
gcov_type *values[GCOV_COUNTERS];
|
||||
const struct gcov_fn_info *fi_ptr;
|
||||
unsigned fi_stride;
|
||||
unsigned c_ix, f_ix, n_counts;
|
||||
struct gcov_ctr_summary *cs_obj, *cs_tobj, *cs_prg, *cs_tprg, *cs_all;
|
||||
unsigned n_counts;
|
||||
struct gcov_summary prg; /* summary for this object over all
|
||||
program. */
|
||||
struct gcov_ctr_summary *cs_prg, *cs_tprg, *cs_all;
|
||||
int error = 0;
|
||||
gcov_unsigned_t tag, length;
|
||||
gcov_position_t summary_pos = 0;
|
||||
gcov_position_t eof_pos = 0;
|
||||
const char *fname, *s;
|
||||
struct gcov_fn_buffer *fn_buffer = 0;
|
||||
struct gcov_fn_buffer **fn_tail = &fn_buffer;
|
||||
|
||||
fname = gi_ptr->filename;
|
||||
|
||||
memset (&this_object, 0, sizeof (this_object));
|
||||
memset (&object, 0, sizeof (object));
|
||||
|
||||
/* Avoid to add multiple drive letters into combined path. */
|
||||
if (prefix_length != 0 && HAS_DRIVE_SPEC(fname))
|
||||
fname += 2;
|
||||
@ -283,6 +353,7 @@ gcov_exit (void)
|
||||
level++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update complete filename with stripped original. */
|
||||
if (prefix_length != 0 && !IS_DIR_SEPARATOR (*fname))
|
||||
{
|
||||
@ -293,42 +364,6 @@ gcov_exit (void)
|
||||
else
|
||||
strcpy (gi_filename_up, fname);
|
||||
|
||||
/* Totals for this object file. */
|
||||
ci_ptr = gi_ptr->counts;
|
||||
for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
|
||||
{
|
||||
if (!((1 << t_ix) & gi_ptr->ctr_mask))
|
||||
continue;
|
||||
|
||||
cs_ptr = &this_object.ctrs[t_ix];
|
||||
cs_ptr->num += ci_ptr->num;
|
||||
for (c_num = 0; c_num < ci_ptr->num; c_num++)
|
||||
{
|
||||
cs_ptr->sum_all += ci_ptr->values[c_num];
|
||||
if (cs_ptr->run_max < ci_ptr->values[c_num])
|
||||
cs_ptr->run_max = ci_ptr->values[c_num];
|
||||
}
|
||||
|
||||
ci_ptr++;
|
||||
}
|
||||
|
||||
c_ix = 0;
|
||||
for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
|
||||
if ((1 << t_ix) & gi_ptr->ctr_mask)
|
||||
{
|
||||
values[c_ix] = gi_ptr->counts[c_ix].values;
|
||||
c_ix++;
|
||||
}
|
||||
|
||||
/* Calculate the function_info stride. This depends on the
|
||||
number of counter types being measured. */
|
||||
fi_stride = sizeof (struct gcov_fn_info) + c_ix * sizeof (unsigned);
|
||||
if (__alignof__ (struct gcov_fn_info) > sizeof (unsigned))
|
||||
{
|
||||
fi_stride += __alignof__ (struct gcov_fn_info) - 1;
|
||||
fi_stride &= ~(__alignof__ (struct gcov_fn_info) - 1);
|
||||
}
|
||||
|
||||
if (!gcov_open (gi_filename))
|
||||
{
|
||||
/* Open failed likely due to missed directory.
|
||||
@ -364,83 +399,98 @@ gcov_exit (void)
|
||||
/* Read from a different compilation. Overwrite the file. */
|
||||
goto rewrite;
|
||||
|
||||
/* Merge execution counts for each function. */
|
||||
for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
|
||||
/* Look for program summary. */
|
||||
for (f_ix = ~0u;;)
|
||||
{
|
||||
fi_ptr = (const struct gcov_fn_info *)
|
||||
((const char *) gi_ptr->functions + f_ix * fi_stride);
|
||||
struct gcov_summary tmp;
|
||||
|
||||
eof_pos = gcov_position ();
|
||||
tag = gcov_read_unsigned ();
|
||||
if (tag != GCOV_TAG_PROGRAM_SUMMARY)
|
||||
break;
|
||||
|
||||
length = gcov_read_unsigned ();
|
||||
if (length != GCOV_TAG_SUMMARY_LENGTH)
|
||||
goto read_mismatch;
|
||||
gcov_read_summary (&tmp);
|
||||
if ((error = gcov_is_error ()))
|
||||
goto read_error;
|
||||
if (!summary_pos && tmp.checksum == gcov_crc32)
|
||||
{
|
||||
prg = tmp;
|
||||
summary_pos = eof_pos;
|
||||
}
|
||||
}
|
||||
|
||||
/* Merge execution counts for each function. */
|
||||
for (f_ix = 0; f_ix != gi_ptr->n_functions;
|
||||
f_ix++, tag = gcov_read_unsigned ())
|
||||
{
|
||||
gfi_ptr = gi_ptr->functions[f_ix];
|
||||
|
||||
if (tag != GCOV_TAG_FUNCTION)
|
||||
goto read_mismatch;
|
||||
length = gcov_read_unsigned ();
|
||||
|
||||
/* Check function. */
|
||||
if (tag != GCOV_TAG_FUNCTION
|
||||
|| length != GCOV_TAG_FUNCTION_LENGTH
|
||||
|| gcov_read_unsigned () != fi_ptr->ident
|
||||
|| gcov_read_unsigned () != fi_ptr->lineno_checksum
|
||||
|| gcov_read_unsigned () != fi_ptr->cfg_checksum)
|
||||
if (!length)
|
||||
/* This function did not appear in the other program.
|
||||
We have nothing to merge. */
|
||||
continue;
|
||||
|
||||
if (length != GCOV_TAG_FUNCTION_LENGTH)
|
||||
goto read_mismatch;
|
||||
|
||||
if (!gfi_ptr || gfi_ptr->key != gi_ptr)
|
||||
{
|
||||
read_mismatch:;
|
||||
fprintf (stderr, "profiling:%s:Merge mismatch for %s\n",
|
||||
gi_filename,
|
||||
f_ix + 1 ? "function" : "summaries");
|
||||
goto read_fatal;
|
||||
/* This function appears in the other program. We
|
||||
need to buffer the information in order to write
|
||||
it back out -- we'll be inserting data before
|
||||
this point, so cannot simply keep the data in the
|
||||
file. */
|
||||
fn_tail = buffer_fn_data (gi_ptr, fn_tail, f_ix);
|
||||
if (!fn_tail)
|
||||
goto read_mismatch;
|
||||
continue;
|
||||
}
|
||||
|
||||
c_ix = 0;
|
||||
if (gcov_read_unsigned () != gfi_ptr->ident
|
||||
|| gcov_read_unsigned () != gfi_ptr->lineno_checksum
|
||||
|| gcov_read_unsigned () != gfi_ptr->cfg_checksum)
|
||||
goto read_mismatch;
|
||||
|
||||
ci_ptr = gfi_ptr->ctrs;
|
||||
for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
|
||||
{
|
||||
gcov_merge_fn merge;
|
||||
gcov_merge_fn merge = gi_ptr->merge[t_ix];
|
||||
|
||||
if (!((1 << t_ix) & gi_ptr->ctr_mask))
|
||||
if (!merge)
|
||||
continue;
|
||||
|
||||
n_counts = fi_ptr->n_ctrs[c_ix];
|
||||
merge = gi_ptr->counts[c_ix].merge;
|
||||
|
||||
tag = gcov_read_unsigned ();
|
||||
length = gcov_read_unsigned ();
|
||||
if (tag != GCOV_TAG_FOR_COUNTER (t_ix)
|
||||
|| length != GCOV_TAG_COUNTER_LENGTH (n_counts))
|
||||
|| length != GCOV_TAG_COUNTER_LENGTH (ci_ptr->num))
|
||||
goto read_mismatch;
|
||||
(*merge) (values[c_ix], n_counts);
|
||||
values[c_ix] += n_counts;
|
||||
c_ix++;
|
||||
(*merge) (ci_ptr->values, ci_ptr->num);
|
||||
ci_ptr++;
|
||||
}
|
||||
if ((error = gcov_is_error ()))
|
||||
goto read_error;
|
||||
}
|
||||
|
||||
f_ix = ~0u;
|
||||
/* Check program & object summary */
|
||||
while (1)
|
||||
if (tag)
|
||||
{
|
||||
int is_program;
|
||||
|
||||
eof_pos = gcov_position ();
|
||||
tag = gcov_read_unsigned ();
|
||||
if (!tag)
|
||||
break;
|
||||
|
||||
length = gcov_read_unsigned ();
|
||||
is_program = tag == GCOV_TAG_PROGRAM_SUMMARY;
|
||||
if (length != GCOV_TAG_SUMMARY_LENGTH
|
||||
|| (!is_program && tag != GCOV_TAG_OBJECT_SUMMARY))
|
||||
goto read_mismatch;
|
||||
gcov_read_summary (is_program ? &program : &object);
|
||||
if ((error = gcov_is_error ()))
|
||||
goto read_error;
|
||||
if (is_program && program.checksum == gcov_crc32)
|
||||
{
|
||||
summary_pos = eof_pos;
|
||||
goto rewrite;
|
||||
}
|
||||
read_mismatch:;
|
||||
fprintf (stderr, "profiling:%s:Merge mismatch for %s\n",
|
||||
gi_filename, f_ix + 1 ? "function" : "summaries");
|
||||
goto read_fatal;
|
||||
}
|
||||
}
|
||||
goto rewrite;
|
||||
|
||||
read_error:;
|
||||
fprintf (stderr, error < 0 ? "profiling:%s:Overflow merging\n"
|
||||
: "profiling:%s:Error merging\n", gi_filename);
|
||||
fprintf (stderr, "profiling:%s:%s merging\n", gi_filename,
|
||||
error < 0 ? "Overflow": "Error");
|
||||
|
||||
read_fatal:;
|
||||
gcov_close ();
|
||||
@ -449,29 +499,20 @@ gcov_exit (void)
|
||||
rewrite:;
|
||||
gcov_rewrite ();
|
||||
if (!summary_pos)
|
||||
memset (&program, 0, sizeof (program));
|
||||
{
|
||||
memset (&prg, 0, sizeof (prg));
|
||||
summary_pos = eof_pos;
|
||||
}
|
||||
|
||||
/* Merge the summaries. */
|
||||
f_ix = ~0u;
|
||||
for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
|
||||
{
|
||||
cs_obj = &object.ctrs[t_ix];
|
||||
cs_tobj = &this_object.ctrs[t_ix];
|
||||
cs_prg = &program.ctrs[t_ix];
|
||||
cs_tprg = &this_program.ctrs[t_ix];
|
||||
cs_all = &all.ctrs[t_ix];
|
||||
cs_prg = &prg.ctrs[t_ix];
|
||||
cs_tprg = &this_prg.ctrs[t_ix];
|
||||
cs_all = &all_prg.ctrs[t_ix];
|
||||
|
||||
if ((1 << t_ix) & gi_ptr->ctr_mask)
|
||||
if (gi_ptr->merge[t_ix])
|
||||
{
|
||||
if (!cs_obj->runs++)
|
||||
cs_obj->num = cs_tobj->num;
|
||||
else if (cs_obj->num != cs_tobj->num)
|
||||
goto read_mismatch;
|
||||
cs_obj->sum_all += cs_tobj->sum_all;
|
||||
if (cs_obj->run_max < cs_tobj->run_max)
|
||||
cs_obj->run_max = cs_tobj->run_max;
|
||||
cs_obj->sum_max += cs_tobj->run_max;
|
||||
|
||||
if (!cs_prg->runs++)
|
||||
cs_prg->num = cs_tprg->num;
|
||||
else if (cs_prg->num != cs_tprg->num)
|
||||
@ -481,78 +522,94 @@ gcov_exit (void)
|
||||
cs_prg->run_max = cs_tprg->run_max;
|
||||
cs_prg->sum_max += cs_tprg->run_max;
|
||||
}
|
||||
else if (cs_obj->num || cs_prg->num)
|
||||
else if (cs_prg->runs)
|
||||
goto read_mismatch;
|
||||
|
||||
if (!cs_all->runs && cs_prg->runs)
|
||||
memcpy (cs_all, cs_prg, sizeof (*cs_all));
|
||||
else if (!all.checksum
|
||||
else if (!all_prg.checksum
|
||||
&& (!GCOV_LOCKED || cs_all->runs == cs_prg->runs)
|
||||
&& memcmp (cs_all, cs_prg, sizeof (*cs_all)))
|
||||
{
|
||||
fprintf (stderr, "profiling:%s:Invocation mismatch - some data files may have been removed%s",
|
||||
fprintf (stderr, "profiling:%s:Invocation mismatch - some data files may have been removed%s\n",
|
||||
gi_filename, GCOV_LOCKED
|
||||
? "" : " or concurrent update without locking support");
|
||||
all.checksum = ~0u;
|
||||
? "" : " or concurrently updated without locking support");
|
||||
all_prg.checksum = ~0u;
|
||||
}
|
||||
}
|
||||
|
||||
c_ix = 0;
|
||||
for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
|
||||
if ((1 << t_ix) & gi_ptr->ctr_mask)
|
||||
{
|
||||
values[c_ix] = gi_ptr->counts[c_ix].values;
|
||||
c_ix++;
|
||||
}
|
||||
|
||||
program.checksum = gcov_crc32;
|
||||
prg.checksum = gcov_crc32;
|
||||
|
||||
/* Write out the data. */
|
||||
gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION);
|
||||
gcov_write_unsigned (gi_ptr->stamp);
|
||||
if (!eof_pos)
|
||||
{
|
||||
gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION);
|
||||
gcov_write_unsigned (gi_ptr->stamp);
|
||||
}
|
||||
|
||||
if (summary_pos)
|
||||
gcov_seek (summary_pos);
|
||||
|
||||
/* Generate whole program statistics. */
|
||||
gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &prg);
|
||||
|
||||
if (summary_pos < eof_pos)
|
||||
gcov_seek (eof_pos);
|
||||
|
||||
/* Write execution counts for each function. */
|
||||
for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
|
||||
{
|
||||
fi_ptr = (const struct gcov_fn_info *)
|
||||
((const char *) gi_ptr->functions + f_ix * fi_stride);
|
||||
unsigned buffered = 0;
|
||||
|
||||
/* Announce function. */
|
||||
gcov_write_tag_length (GCOV_TAG_FUNCTION, GCOV_TAG_FUNCTION_LENGTH);
|
||||
gcov_write_unsigned (fi_ptr->ident);
|
||||
gcov_write_unsigned (fi_ptr->lineno_checksum);
|
||||
gcov_write_unsigned (fi_ptr->cfg_checksum);
|
||||
if (fn_buffer && fn_buffer->fn_ix == f_ix)
|
||||
{
|
||||
/* Buffered data from another program. */
|
||||
buffered = 1;
|
||||
gfi_ptr = &fn_buffer->info;
|
||||
length = GCOV_TAG_FUNCTION_LENGTH;
|
||||
}
|
||||
else
|
||||
{
|
||||
gfi_ptr = gi_ptr->functions[f_ix];
|
||||
if (gfi_ptr && gfi_ptr->key == gi_ptr)
|
||||
length = GCOV_TAG_FUNCTION_LENGTH;
|
||||
else
|
||||
length = 0;
|
||||
}
|
||||
|
||||
gcov_write_tag_length (GCOV_TAG_FUNCTION, length);
|
||||
if (!length)
|
||||
continue;
|
||||
|
||||
gcov_write_unsigned (gfi_ptr->ident);
|
||||
gcov_write_unsigned (gfi_ptr->lineno_checksum);
|
||||
gcov_write_unsigned (gfi_ptr->cfg_checksum);
|
||||
|
||||
c_ix = 0;
|
||||
ci_ptr = gfi_ptr->ctrs;
|
||||
for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
|
||||
{
|
||||
gcov_type *c_ptr;
|
||||
|
||||
if (!((1 << t_ix) & gi_ptr->ctr_mask))
|
||||
if (!gi_ptr->merge[t_ix])
|
||||
continue;
|
||||
|
||||
n_counts = fi_ptr->n_ctrs[c_ix];
|
||||
|
||||
n_counts = ci_ptr->num;
|
||||
gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
|
||||
GCOV_TAG_COUNTER_LENGTH (n_counts));
|
||||
c_ptr = values[c_ix];
|
||||
gcov_type *c_ptr = ci_ptr->values;
|
||||
while (n_counts--)
|
||||
gcov_write_counter (*c_ptr++);
|
||||
|
||||
values[c_ix] = c_ptr;
|
||||
c_ix++;
|
||||
if (buffered)
|
||||
free (ci_ptr->values);
|
||||
ci_ptr++;
|
||||
}
|
||||
if (buffered)
|
||||
{
|
||||
struct gcov_fn_buffer *tmp = fn_buffer;
|
||||
fn_buffer = fn_buffer->next;
|
||||
free (tmp);
|
||||
}
|
||||
}
|
||||
|
||||
/* Object file summary. */
|
||||
gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, &object);
|
||||
|
||||
/* Generate whole program statistics. */
|
||||
if (eof_pos)
|
||||
gcov_seek (eof_pos);
|
||||
gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &program);
|
||||
if (!summary_pos)
|
||||
gcov_write_unsigned (0);
|
||||
gcov_write_unsigned (0);
|
||||
if ((error = gcov_close ()))
|
||||
fprintf (stderr, error < 0 ?
|
||||
"profiling:%s:Overflow writing\n" :
|
||||
@ -618,15 +675,25 @@ __gcov_flush (void)
|
||||
gcov_exit ();
|
||||
for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
|
||||
{
|
||||
unsigned t_ix;
|
||||
const struct gcov_ctr_info *ci_ptr;
|
||||
unsigned f_ix;
|
||||
|
||||
for (t_ix = 0, ci_ptr = gi_ptr->counts; t_ix != GCOV_COUNTERS; t_ix++)
|
||||
if ((1 << t_ix) & gi_ptr->ctr_mask)
|
||||
{
|
||||
memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
|
||||
ci_ptr++;
|
||||
}
|
||||
for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
|
||||
{
|
||||
unsigned t_ix;
|
||||
const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
|
||||
|
||||
if (!gfi_ptr || gfi_ptr->key != gi_ptr)
|
||||
continue;
|
||||
const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
|
||||
for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
|
||||
{
|
||||
if (!gi_ptr->merge[t_ix])
|
||||
continue;
|
||||
|
||||
memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
|
||||
ci_ptr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user