aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog74
-rw-r--r--gcc/Makefile.in4
-rw-r--r--gcc/basic-block.h4
-rw-r--r--gcc/coverage.c841
-rw-r--r--gcc/coverage.h44
-rw-r--r--gcc/gcov-dump.c41
-rw-r--r--gcc/gcov-io.c32
-rw-r--r--gcc/gcov-io.h89
-rw-r--r--gcc/gcov.c8
-rw-r--r--gcc/libgcov.c420
-rw-r--r--gcc/mklibgcc.in2
-rw-r--r--gcc/predict.c21
-rw-r--r--gcc/profile.c38
-rw-r--r--gcc/tracer.c4
14 files changed, 698 insertions, 924 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index ce22865..0c18f2f 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,77 @@
+2003-04-23 Nathan Sidwell <nathan@codesourcery.com>
+
+ * Makefile.in (LIBGCC_DEPS): Add gcov headers.
+ (libgcov.a): Depends on LIBGCC_DEPS.
+ * basic-block.h (profile_info): Moved here from coverage.h. Made
+ a pointer.
+ * coverage.c (struct function_list): Fixed array of counter types.
+ (struct counts_entry): Keyed by counter type, contains summary.
+ (profile_info): Moved to profile.c.
+ (prg_ctr_mask, prg_n_ctrs, fn_ctr_mask, fn_n_ctrs): New global
+ vars.
+ (profiler_label): Remove.
+ (ctr_labels): New.
+ (set_purpose, label_for_tag, build_counter_section_fields,
+ build_counter_section_value, build_counter_section_data_fields,
+ build_counter_section_data_values, build_function_info_fields,
+ build_function_info_value, gcov_info_fields, gcov_info_value): Remove.
+ (build_fn_info_type, build_fn_info_value, build_ctr_info_type,
+ build_ctr_info_value, build_gcov_info): New.
+ (htab_counts_entry_hash, htab_counts_entry_eq): Adjust.
+ (reads_counts_file): Adjust.
+ (get_coverage_counts): Takes counter number. Add summary
+ parameter. Adjust.
+ (coverage_counter_ref): Tkaes counter number. Adjust. Lazily
+ create counter array labels.
+ (coverage_end_function): Adjust.
+ (create_coverage): Adjust.
+ (find_counters_section): Remove.
+ * coverage.h (MAX_COUNTER_SECTIONS): Remove.
+ (struct section_info, struct profile_info): Remove.
+ (profile_info): Moved to basic-block.h.
+ (coverage_counter_ref): Takes a counter number.
+ (get_coverage_counts): Takes a counter number. Added summary
+ parameter.
+ (find_counters_section): Remove.
+ * gcov-dump.c (tag_arc_counts): Rename to ...
+ (tag_counters): ... here. Adjust.
+ (tag_table): Move tag_counters to 3rd entry. Remove
+ PROGRAM_PLACEHOLDER and PROGRAM_INCORRECT entries.
+ (dump_file): Check for counter tag values here.
+ (tag_summary): Adjust.
+ * gcov-io.c (gcov_write_summary, gcov_read_summary): Adjust.
+ * gcov-io.h (GCOV_LOCKED): New.
+ (GCOV_TAG_ARC_COUNTS): Rename to ...
+ (GCOV_TAG_COUNTS_BASE): ... here.
+ (GCOV_TAG_PLACEHOLDER_SUMMARY, GCOV_TAG_INCORRECT_SUMMARY):
+ Remove.
+ (GCOV_COUNTER_ARCS, GCOV_COUNTERS, GCOV_NAMES): New.
+ (GCOV_TAG_FOR_COUNTER, GCOV_COUNTER_FOR_TAG,
+ GCOV_TAG_IS_COUNTER): New.
+ (struct gcov_ctr_summary): New.
+ (struct gcov_summary): Adjust.
+ (struct gcov_counter_section): Remove.
+ struct gcov_counter_section_data): Remove.
+ (struct gcov_function_info): Rename to ...
+ (struct gcov_fn_info): ... here. Adjust.
+ (struct gcov_ctr_info): New.
+ (struct gcov_info): Adjust.
+ * gcov.c (read_count_file): Adjust.
+ (output_lines): Adjust.
+ * libgcov.c (gcov_exit): Adjust.
+ (__gcov_flush): Adjust.
+ * mklibgcc.in (libgcc2_c_dep): Add gcov headers.
+ * predict.c (maybe_hot_bb_p, probably_cold_bb_p,
+ probably_never_executed_bb_p, compute_frequency_function): Adjust
+ profile_info use.
+ * profile.c (struct counts_entry): Remove.
+ (profile_info): Define here.
+ (get_exec_counts): Adjust get_coverage_counts call.
+ (compute_branch_probablilities): Remove find_counters_section
+ call.
+ (gen_edge_profiler): Adjust coverage_counter_ref call.
+ * tracer.c (tail_duplicate): Adjust profile_info use.
+
2003-04-23 Roger Sayle <roger@eyesopen.com>
PR optimization/10339
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index b8a6bb0..d82f5b00 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1112,9 +1112,9 @@ LIBGCC_DEPS = $(GCC_PASSES) $(LANGUAGES) stmp-int-hdrs $(STMP_FIXPROTO) \
$(MACHMODE_H) longlong.h gbl-ctors.h config.status stmp-int-hdrs \
tsystem.h $(FPBIT) $(DPBIT) $(TPBIT) $(LIB2ADD) \
$(LIB2ADD_ST) $(LIB2ADDEH) $(LIB2ADDEHDEP) $(EXTRA_PARTS) \
- $(srcdir)/config/$(LIB1ASMSRC)
+ $(srcdir)/config/$(LIB1ASMSRC) gcov-io.h gcov-io.c gcov-iov.h
-libgcov.a: libgcc.a; @true
+libgcov.a: $(LIBGCC_DEPS); @true
libgcc.a: $(LIBGCC_DEPS)
$(MAKE) GCC_FOR_TARGET="$(GCC_FOR_TARGET)" \
diff --git a/gcc/basic-block.h b/gcc/basic-block.h
index fce7de5..4c8d5e3 100644
--- a/gcc/basic-block.h
+++ b/gcc/basic-block.h
@@ -155,6 +155,10 @@ typedef struct edge_def {
#define EDGE_COMPLEX (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL | EDGE_EH)
+/* Counter summary from the last set of coverage counts read by
+ profile.c. */
+extern const struct gcov_ctr_summary *profile_info;
+
/* Declared in cfgloop.h. */
struct loop;
struct loops;
diff --git a/gcc/coverage.c b/gcc/coverage.c
index 07c56a3..421b3b1 100644
--- a/gcc/coverage.c
+++ b/gcc/coverage.c
@@ -49,12 +49,10 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
struct function_list
{
- struct function_list *next; /* next function */
- const char *name; /* function name */
- unsigned cfg_checksum; /* function checksum */
- unsigned n_counter_sections; /* number of counter sections */
- struct gcov_counter_section counter_sections[MAX_COUNTER_SECTIONS];
- /* the sections */
+ struct function_list *next; /* next function */
+ const char *name; /* function name */
+ unsigned checksum; /* function checksum */
+ unsigned n_ctrs[GCOV_COUNTERS];/* number of counters. */
};
/* Counts information for a function. */
@@ -62,15 +60,12 @@ typedef struct counts_entry
{
/* We hash by */
char *function_name;
- unsigned section;
+ unsigned ctr;
/* Store */
unsigned checksum;
- unsigned n_counts;
gcov_type *counts;
- unsigned merged;
- gcov_type max_counter;
- gcov_type max_counter_sum;
+ struct gcov_ctr_summary summary;
/* Workspace */
struct counts_entry *chain;
@@ -80,9 +75,13 @@ typedef struct counts_entry
static struct function_list *functions_head = 0;
static struct function_list **functions_tail = &functions_head;
-/* Instantiate the profile info structure. */
+/* Cumulative counter information for whole program. */
+static unsigned prg_ctr_mask; /* Mask of counter types generated. */
+static unsigned prg_n_ctrs[GCOV_COUNTERS];
-struct profile_info profile_info;
+/* Counter information for current function. */
+static unsigned fn_ctr_mask;
+static unsigned fn_n_ctrs[GCOV_COUNTERS];
/* Name of the output file for coverage output file. */
static char *bbg_file_name;
@@ -95,8 +94,8 @@ static char *da_file_name;
/* Hash table of count data. */
static htab_t counts_hash = NULL;
-/* The name of the count table. Used by the edge profiling code. */
-static GTY(()) rtx profiler_label;
+/* The names of the counter tables. */
+static GTY(()) rtx ctr_labels[GCOV_COUNTERS];
/* Forward declarations. */
static hashval_t htab_counts_entry_hash PARAMS ((const void *));
@@ -105,16 +104,11 @@ static void htab_counts_entry_del PARAMS ((void *));
static void read_counts_file PARAMS ((void));
static unsigned compute_checksum PARAMS ((void));
static unsigned checksum_string PARAMS ((unsigned, const char *));
-static void set_purpose PARAMS ((tree, tree));
-static rtx label_for_tag PARAMS ((unsigned));
-static tree build_counter_section_fields PARAMS ((void));
-static tree build_counter_section_value PARAMS ((unsigned, unsigned));
-static tree build_counter_section_data_fields PARAMS ((void));
-static tree build_counter_section_data_value PARAMS ((unsigned, unsigned));
-static tree build_function_info_fields PARAMS ((void));
-static tree build_function_info_value PARAMS ((struct function_list *));
-static tree build_gcov_info_fields PARAMS ((tree));
-static tree build_gcov_info_value PARAMS ((void));
+static tree build_fn_info_type PARAMS ((unsigned));
+static tree build_fn_info_value PARAMS ((const struct function_list *, tree));
+static tree build_ctr_info_type PARAMS ((void));
+static tree build_ctr_info_value PARAMS ((unsigned, tree));
+static tree build_gcov_info PARAMS ((void));
static void create_coverage PARAMS ((void));
@@ -124,7 +118,7 @@ htab_counts_entry_hash (of)
{
const counts_entry_t *entry = of;
- return htab_hash_string (entry->function_name) ^ entry->section;
+ return htab_hash_string (entry->function_name) ^ entry->ctr;
}
static int
@@ -136,7 +130,7 @@ htab_counts_entry_eq (of1, of2)
const counts_entry_t *entry2 = of2;
return !strcmp (entry1->function_name, entry2->function_name)
- && entry1->section == entry2->section;
+ && entry1->ctr == entry2->ctr;
}
static void
@@ -213,8 +207,6 @@ read_counts_file ()
for (entry = summaried; entry; entry = chain)
{
chain = entry->chain;
-
- entry->max_counter_sum += entry->max_counter;
entry->chain = NULL;
}
summaried = NULL;
@@ -230,34 +222,38 @@ read_counts_file ()
seen_summary = 1;
for (entry = summaried; entry; entry = entry->chain)
{
- entry->merged += summary.runs;
- if (entry->max_counter < summary.arc_sum_max)
- entry->max_counter = summary.arc_sum_max;
+ 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;
}
}
- else if (GCOV_TAG_IS_SUBTAG (GCOV_TAG_FUNCTION, tag)
- && function_name_buffer)
+ else if (GCOV_TAG_IS_COUNTER (tag) && function_name_buffer)
{
counts_entry_t **slot, *entry, elt;
unsigned n_counts = length / 8;
unsigned ix;
elt.function_name = function_name_buffer;
- elt.section = tag;
+ elt.ctr = GCOV_COUNTER_FOR_TAG (tag);
slot = (counts_entry_t **) htab_find_slot
(counts_hash, &elt, INSERT);
entry = *slot;
if (!entry)
{
- *slot = entry = xmalloc (sizeof (counts_entry_t));
- entry->function_name = xstrdup (function_name_buffer);
- entry->section = tag;
+ *slot = entry = xcalloc (1, sizeof (counts_entry_t));
+ entry->function_name = xstrdup (elt.function_name);
+ entry->ctr = elt.ctr;
entry->checksum = checksum;
- entry->n_counts = n_counts;
+ entry->summary.num = n_counts;
entry->counts = xcalloc (n_counts, sizeof (gcov_type));
}
- else if (entry->checksum != checksum || entry->n_counts != n_counts)
+ else if (entry->checksum != checksum
+ || entry->summary.num != n_counts)
{
warning ("profile mismatch for `%s'", function_name_buffer);
htab_delete (counts_hash);
@@ -292,13 +288,11 @@ read_counts_file ()
/* Returns the counters for a particular tag. */
gcov_type *
-get_coverage_counts (unsigned tag, unsigned expected)
+get_coverage_counts (unsigned counter, unsigned expected,
+ const struct gcov_ctr_summary **summary)
{
counts_entry_t *entry, elt;
- profile_info.max_counter_in_program = 0;
- profile_info.count_profiles_merged = 0;
-
/* No hash table, no counts. */
if (!counts_hash)
{
@@ -313,7 +307,7 @@ get_coverage_counts (unsigned tag, unsigned expected)
elt.function_name
= (char *) IDENTIFIER_POINTER
(DECL_ASSEMBLER_NAME (current_function_decl));
- elt.section = tag;
+ elt.ctr = counter;
entry = htab_find (counts_hash, &elt);
if (!entry)
{
@@ -321,18 +315,49 @@ get_coverage_counts (unsigned tag, unsigned expected)
return 0;
}
- if (expected != entry->n_counts
+ if (expected != entry->summary.num
|| compute_checksum () != entry->checksum)
{
warning ("profile mismatch for `%s'", elt.function_name);
return NULL;
}
- profile_info.count_profiles_merged = entry->merged;
- profile_info.max_counter_in_program = entry->max_counter_sum;
+ if (summary)
+ *summary = &entry->summary;
return entry->counts;
}
+
+/* Generate a MEM rtl to access COUNTER NO . */
+
+rtx
+coverage_counter_ref (unsigned counter, unsigned no)
+{
+ enum machine_mode mode = mode_for_size (GCOV_TYPE_SIZE, MODE_INT, 0);
+ rtx ref;
+
+ if (!ctr_labels[counter])
+ {
+ /* Generate and save a copy of this so it can be shared. */
+ char buf[20];
+
+ ASM_GENERATE_INTERNAL_LABEL (buf, "LPBX", counter + 1);
+ ctr_labels[counter] = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
+ }
+ if (no + 1 > fn_n_ctrs[counter])
+ {
+ fn_n_ctrs[counter] = no + 1;
+ fn_ctr_mask |= 1 << counter;
+ }
+
+ no += prg_n_ctrs[counter];
+ ref = plus_constant (ctr_labels[counter],
+ GCOV_TYPE_SIZE / BITS_PER_UNIT * no);
+ ref = gen_rtx_MEM (mode, ref);
+ set_mem_alias_set (ref, new_alias_set ());
+
+ return ref;
+}
/* Generate a checksum for a string. CHKSUM is the current
checksum. */
@@ -426,415 +451,236 @@ coverage_end_function ()
warning ("error writing `%s'", bbg_file_name);
bbg_file_opened = -1;
}
-
- for (i = 0; i != profile_info.n_sections; i++)
- if (profile_info.section_info[i].n_counters_now)
- {
- struct function_list *item;
+
+ if (fn_ctr_mask)
+ {
+ struct function_list *item;
- /* ??? Probably should re-use the existing struct function. */
- item = xmalloc (sizeof (struct function_list));
+ /* ??? Probably should re-use the existing struct function. */
+ item = xmalloc (sizeof (struct function_list));
- *functions_tail = item;
- functions_tail = &item->next;
+ *functions_tail = item;
+ functions_tail = &item->next;
- item->next = 0;
- item->name = xstrdup (IDENTIFIER_POINTER
- (DECL_ASSEMBLER_NAME (current_function_decl)));
- item->cfg_checksum = compute_checksum ();
- item->n_counter_sections = 0;
- for (i = 0; i < profile_info.n_sections; i++)
- if (profile_info.section_info[i].n_counters_now)
- {
- item->counter_sections[item->n_counter_sections].tag =
- profile_info.section_info[i].tag;
- item->counter_sections[item->n_counter_sections].n_counters =
- profile_info.section_info[i].n_counters_now;
- item->n_counter_sections++;
- profile_info.section_info[i].n_counters
- += profile_info.section_info[i].n_counters_now;
- profile_info.section_info[i].n_counters_now = 0;
- }
- break;
- }
+ item->next = 0;
+ item->name = xstrdup (IDENTIFIER_POINTER
+ (DECL_ASSEMBLER_NAME (current_function_decl)));
+ item->checksum = compute_checksum ();
+ 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] = 0;
+ }
+ prg_ctr_mask |= fn_ctr_mask;
+ fn_ctr_mask = 0;
+ }
bbg_function_announced = 0;
}
-/* Set FIELDS as purpose to VALUE. */
-static void
-set_purpose (value, fields)
- tree value;
- tree fields;
-{
- tree act_field, act_value;
-
- for (act_field = fields, act_value = value;
- act_field;
- act_field = TREE_CHAIN (act_field), act_value = TREE_CHAIN (act_value))
- TREE_PURPOSE (act_value) = act_field;
-}
+/* Creates the gcov_fn_info RECORD_TYPE. */
-/* Returns label for base of counters inside TAG section. */
-static rtx
-label_for_tag (tag)
- unsigned tag;
-{
- switch (tag)
- {
- case GCOV_TAG_ARC_COUNTS:
- return profiler_label;
- default:
- abort ();
- }
-}
-
-/* Creates fields of struct counter_section (in gcov-io.h). */
static tree
-build_counter_section_fields ()
+build_fn_info_type (counters)
+ unsigned counters;
{
+ tree type = (*lang_hooks.types.make_type) (RECORD_TYPE);
tree field, fields;
-
- /* tag */
- fields = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
-
- /* n_counters */
- field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
- TREE_CHAIN (field) = fields;
- fields = field;
-
- return fields;
-}
-
-/* Creates value of struct counter_section (in gcov-io.h). */
-static tree
-build_counter_section_value (tag, n_counters)
- unsigned tag;
- unsigned n_counters;
-{
- tree value = NULL_TREE;
-
- /* tag */
- value = tree_cons (NULL_TREE,
- convert (unsigned_type_node,
- build_int_2 (tag, 0)),
- value);
-
- /* n_counters */
- value = tree_cons (NULL_TREE,
- convert (unsigned_type_node,
- build_int_2 (n_counters, 0)),
- value);
-
- return value;
-}
-
-/* Creates fields of struct counter_section_data (in gcov-io.h). */
-static tree
-build_counter_section_data_fields ()
-{
- tree field, fields, gcov_type, gcov_ptr_type;
-
- gcov_type = make_signed_type (GCOV_TYPE_SIZE);
- gcov_ptr_type =
- build_pointer_type (build_qualified_type (gcov_type,
+ tree string_type =
+ build_pointer_type (build_qualified_type (char_type_node,
TYPE_QUAL_CONST));
+ tree array_type;
+
+ /* name */
+ fields = build_decl (FIELD_DECL, NULL_TREE, string_type);
- /* tag */
- fields = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
-
- /* n_counters */
+ /* checksum */
field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
TREE_CHAIN (field) = fields;
fields = field;
+ array_type = build_index_type (build_int_2 (counters - 1, 0));
+ array_type = build_array_type (unsigned_type_node, array_type);
+
/* counters */
- field = build_decl (FIELD_DECL, NULL_TREE, gcov_ptr_type);
+ field = build_decl (FIELD_DECL, NULL_TREE, array_type);
TREE_CHAIN (field) = fields;
fields = field;
- return fields;
+ finish_builtin_struct (type, "__gcov_fn_info", fields, NULL_TREE);
+
+ return type;
}
-/* Creates value of struct counter_section_data (in gcov-io.h). */
+/* Creates a CONSTRUCTOR for a gcov_fn_info. FUNCTION is
+ the function being processed and TYPE is the gcov_fn_info
+ RECORD_TYPE. */
+
static tree
-build_counter_section_data_value (tag, n_counters)
- unsigned tag;
- unsigned n_counters;
+build_fn_info_value (function, type)
+ const struct function_list *function;
+ tree type;
{
- tree value = NULL_TREE, counts_table, gcov_type, gcov_ptr_type;
-
- gcov_type = make_signed_type (GCOV_TYPE_SIZE);
- gcov_ptr_type
- = build_pointer_type (build_qualified_type
- (gcov_type, TYPE_QUAL_CONST));
-
- /* tag */
- value = tree_cons (NULL_TREE,
- convert (unsigned_type_node,
- build_int_2 (tag, 0)),
+ tree value = NULL_TREE;
+ tree fields = TYPE_FIELDS (type);
+ size_t name_len = strlen (function->name);
+ tree fname = build_string (name_len + 1, function->name);
+ tree string_type =
+ build_pointer_type (build_qualified_type (char_type_node,
+ TYPE_QUAL_CONST));
+ unsigned ix;
+ tree array_value = NULL_TREE;
+
+ /* name */
+ TREE_TYPE (fname) =
+ build_array_type (char_type_node,
+ build_index_type (build_int_2 (name_len, 0)));
+ value = tree_cons (fields,
+ build1 (ADDR_EXPR, string_type, fname),
value);
+ fields = TREE_CHAIN (fields);
- /* n_counters */
- value = tree_cons (NULL_TREE,
+ /* checksum */
+ value = tree_cons (fields,
convert (unsigned_type_node,
- build_int_2 (n_counters, 0)),
+ build_int_2 (function->checksum, 0)),
value);
-
+ fields = TREE_CHAIN (fields);
+
/* counters */
- if (n_counters)
- {
- tree gcov_type_array_type =
- build_array_type (gcov_type,
- build_index_type (build_int_2 (n_counters - 1,
- 0)));
- counts_table =
- build (VAR_DECL, gcov_type_array_type, NULL_TREE, NULL_TREE);
- TREE_STATIC (counts_table) = 1;
- DECL_NAME (counts_table) = get_identifier (XSTR (label_for_tag (tag), 0));
- assemble_variable (counts_table, 0, 0, 0);
- counts_table = build1 (ADDR_EXPR, gcov_ptr_type, counts_table);
- }
- else
- counts_table = null_pointer_node;
-
- value = tree_cons (NULL_TREE, counts_table, value);
+ for (ix = 0; ix != GCOV_COUNTERS; ix++)
+ if (prg_ctr_mask & (1 << ix))
+ {
+ tree counters = convert (unsigned_type_node,
+ build_int_2 (function->n_ctrs[ix], 0));
+
+ array_value = tree_cons (NULL_TREE, counters, array_value);
+ }
+
+ array_value = build_constructor (TREE_TYPE (fields), nreverse (array_value));
+ value = tree_cons (fields, array_value, value);
+ value = build_constructor (type, nreverse (value));
+
return value;
}
-/* Creates fields for struct function_info type (in gcov-io.h). */
+/* Creates the gcov_ctr_info RECORD_TYPE. */
+
static tree
-build_function_info_fields ()
+build_ctr_info_type ()
{
- tree field, fields, counter_section_fields, counter_section_type;
- tree counter_sections_ptr_type;
- tree string_type =
- build_pointer_type (build_qualified_type (char_type_node,
- TYPE_QUAL_CONST));
- /* name */
- fields = build_decl (FIELD_DECL, NULL_TREE, string_type);
-
- /* checksum */
+ tree type = (*lang_hooks.types.make_type) (RECORD_TYPE);
+ tree field, fields = NULL_TREE;
+
+ /* counters */
field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
TREE_CHAIN (field) = fields;
fields = field;
- /* n_counter_sections */
- field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
+ /* values */
+ field = build_decl (FIELD_DECL, NULL_TREE,
+ build_pointer_type (make_signed_type (GCOV_TYPE_SIZE)));
TREE_CHAIN (field) = fields;
fields = field;
- /* counter_sections */
- counter_section_fields = build_counter_section_fields ();
- counter_section_type = (*lang_hooks.types.make_type) (RECORD_TYPE);
- finish_builtin_struct (counter_section_type, "__counter_section",
- counter_section_fields, NULL_TREE);
- counter_sections_ptr_type =
- build_pointer_type
- (build_qualified_type (counter_section_type,
- TYPE_QUAL_CONST));
- field = build_decl (FIELD_DECL, NULL_TREE, counter_sections_ptr_type);
- TREE_CHAIN (field) = fields;
- fields = field;
+ finish_builtin_struct (type, "__gcov_ctr_info", fields, NULL_TREE);
- return fields;
+ return type;
}
-/* Creates value for struct function_info (in gcov-io.h). */
+/* 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_function_info_value (function)
- struct function_list *function;
+build_ctr_info_value (counter, type)
+ unsigned counter;
+ tree type;
{
tree value = NULL_TREE;
- size_t name_len = strlen (function->name);
- tree fname = build_string (name_len + 1, function->name);
- tree string_type =
- build_pointer_type (build_qualified_type (char_type_node,
- TYPE_QUAL_CONST));
- tree counter_section_fields, counter_section_type, counter_sections_value;
- tree counter_sections_ptr_type, counter_sections_array_type;
- unsigned i;
-
- /* name */
- TREE_TYPE (fname) =
- build_array_type (char_type_node,
- build_index_type (build_int_2 (name_len, 0)));
- value = tree_cons (NULL_TREE,
- build1 (ADDR_EXPR,
- string_type,
- fname),
- value);
+ tree fields = TYPE_FIELDS (type);
- /* checksum */
- value = tree_cons (NULL_TREE,
+ /* counters */
+ value = tree_cons (fields,
convert (unsigned_type_node,
- build_int_2 (function->cfg_checksum, 0)),
+ build_int_2 (prg_n_ctrs[counter], 0)),
value);
+ fields = TREE_CHAIN (fields);
- /* n_counter_sections */
-
- value = tree_cons (NULL_TREE,
- convert (unsigned_type_node,
- build_int_2 (function->n_counter_sections, 0)),
- value);
-
- /* counter_sections */
- counter_section_fields = build_counter_section_fields ();
- counter_section_type = (*lang_hooks.types.make_type) (RECORD_TYPE);
- counter_sections_ptr_type =
- build_pointer_type
- (build_qualified_type (counter_section_type,
- TYPE_QUAL_CONST));
- counter_sections_array_type =
- build_array_type (counter_section_type,
- build_index_type (
- build_int_2 (function->n_counter_sections - 1,
- 0)));
-
- counter_sections_value = NULL_TREE;
- for (i = 0; i < function->n_counter_sections; i++)
- {
- tree counter_section_value
- = build_counter_section_value (function->counter_sections[i].tag,
- function->counter_sections[i].n_counters);
- set_purpose (counter_section_value, counter_section_fields);
- counter_sections_value =
- tree_cons (NULL_TREE,
- build_constructor (counter_section_type,
- nreverse (counter_section_value)),
- counter_sections_value);
- }
- finish_builtin_struct (counter_section_type, "__counter_section",
- counter_section_fields, NULL_TREE);
-
- if (function->n_counter_sections)
+ if (prg_n_ctrs[counter])
{
- counter_sections_value =
- build_constructor (counter_sections_array_type,
- nreverse (counter_sections_value)),
- counter_sections_value = build1 (ADDR_EXPR,
- counter_sections_ptr_type,
- counter_sections_value);
+ tree array_type, array;
+
+ array_type = build_index_type (build_int_2 (prg_n_ctrs[counter] - 1, 0));
+ array_type = build_array_type (TREE_TYPE (TREE_TYPE (fields)),
+ array_type);
+
+ array = build (VAR_DECL, array_type, NULL_TREE, NULL_TREE);
+ TREE_STATIC (array) = 1;
+ DECL_NAME (array) = get_identifier (XSTR (ctr_labels[counter], 0));
+ assemble_variable (array, 0, 0, 0);
+
+ value = tree_cons (fields,
+ build1 (ADDR_EXPR, TREE_TYPE (fields), array),
+ value);
}
else
- counter_sections_value = null_pointer_node;
-
- value = tree_cons (NULL_TREE, counter_sections_value, value);
+ value = tree_cons (fields, null_pointer_node, value);
+ value = build_constructor (type, nreverse (value));
+
return value;
}
-/* Creates fields of struct gcov_info type (in gcov-io.h). */
+/* Creates the gcov_info RECORD_TYPE and initializer for it. Returns a
+ CONSTRUCTOR. */
+
static tree
-build_gcov_info_fields (gcov_info_type)
- tree gcov_info_type;
+build_gcov_info ()
{
- tree field, fields;
+ 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 value = NULL_TREE;
+ tree filename_string;
char *filename;
int filename_len;
- tree string_type =
- build_pointer_type (build_qualified_type (char_type_node,
- TYPE_QUAL_CONST));
- tree function_info_fields, function_info_type, function_info_ptr_type;
- tree counter_section_data_fields, counter_section_data_type;
- tree counter_section_data_ptr_type;
-
- /* Version ident */
- fields = build_decl (FIELD_DECL, NULL_TREE, long_unsigned_type_node);
-
- /* next -- NULL */
- field = build_decl (FIELD_DECL, NULL_TREE,
- build_pointer_type
- (build_qualified_type
- (gcov_info_type, TYPE_QUAL_CONST)));
- TREE_CHAIN (field) = fields;
- fields = field;
+ unsigned n_fns;
+ const struct function_list *fn;
+ tree string_type;
- /* Filename */
- filename = getpwd ();
- filename = (filename && da_file_name[0] != '/'
- ? concat (filename, "/", da_file_name, NULL)
- : da_file_name);
- filename_len = strlen (filename);
- if (filename != da_file_name)
- free (filename);
-
- field = build_decl (FIELD_DECL, NULL_TREE, string_type);
- TREE_CHAIN (field) = fields;
- fields = field;
+ /* 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++;
- /* Workspace */
- field = build_decl (FIELD_DECL, NULL_TREE, long_integer_type_node);
- TREE_CHAIN (field) = fields;
- fields = field;
-
- /* number of functions */
- field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
- TREE_CHAIN (field) = fields;
- fields = field;
-
- /* function_info table */
- function_info_fields = build_function_info_fields ();
- function_info_type = (*lang_hooks.types.make_type) (RECORD_TYPE);
- finish_builtin_struct (function_info_type, "__function_info",
- function_info_fields, NULL_TREE);
- function_info_ptr_type =
- build_pointer_type
- (build_qualified_type (function_info_type,
- TYPE_QUAL_CONST));
- field = build_decl (FIELD_DECL, NULL_TREE, function_info_ptr_type);
- TREE_CHAIN (field) = fields;
- fields = field;
-
- /* n_counter_sections */
- field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
- TREE_CHAIN (field) = fields;
- fields = field;
+ type = (*lang_hooks.types.make_type) (RECORD_TYPE);
+ const_type = build_qualified_type (type, TYPE_QUAL_CONST);
- /* counter sections */
- counter_section_data_fields = build_counter_section_data_fields ();
- counter_section_data_type = (*lang_hooks.types.make_type) (RECORD_TYPE);
- finish_builtin_struct (counter_section_data_type, "__counter_section_data",
- counter_section_data_fields, NULL_TREE);
- counter_section_data_ptr_type =
- build_pointer_type
- (build_qualified_type (counter_section_data_type,
- TYPE_QUAL_CONST));
- field = build_decl (FIELD_DECL, NULL_TREE, counter_section_data_ptr_type);
+ /* Version ident */
+ field = build_decl (FIELD_DECL, NULL_TREE, long_unsigned_type_node);
TREE_CHAIN (field) = fields;
fields = field;
-
- return fields;
-}
-
-/* Creates struct gcov_info value (in gcov-io.h). */
-static tree
-build_gcov_info_value ()
-{
- tree value = NULL_TREE;
- tree filename_string;
- char *filename;
- int filename_len;
- unsigned n_functions, i;
- struct function_list *item;
- tree string_type =
- build_pointer_type (build_qualified_type (char_type_node,
- TYPE_QUAL_CONST));
- tree function_info_fields, function_info_type, function_info_ptr_type;
- tree functions;
- tree counter_section_data_fields, counter_section_data_type;
- tree counter_section_data_ptr_type, counter_sections;
-
- /* Version ident */
- value = tree_cons (NULL_TREE,
- convert (long_unsigned_type_node,
- build_int_2 (GCOV_VERSION, 0)),
+ value = tree_cons (field, convert (long_unsigned_type_node,
+ build_int_2 (GCOV_VERSION, 0)),
value);
-
+
/* next -- NULL */
- value = tree_cons (NULL_TREE, null_pointer_node, value);
+ field = build_decl (FIELD_DECL, NULL_TREE, build_pointer_type (const_type));
+ TREE_CHAIN (field) = fields;
+ fields = field;
+ value = tree_cons (field, null_pointer_node, value);
/* Filename */
+ string_type = build_pointer_type (build_qualified_type (char_type_node,
+ TYPE_QUAL_CONST));
+ field = build_decl (FIELD_DECL, NULL_TREE, string_type);
+ TREE_CHAIN (field) = fields;
+ fields = field;
filename = getpwd ();
filename = (filename && da_file_name[0] != '/'
? concat (filename, "/", da_file_name, NULL)
@@ -846,144 +692,99 @@ build_gcov_info_value ()
TREE_TYPE (filename_string) =
build_array_type (char_type_node,
build_index_type (build_int_2 (filename_len, 0)));
- value = tree_cons (NULL_TREE,
- build1 (ADDR_EXPR,
- string_type,
- filename_string),
+ value = tree_cons (field, build1 (ADDR_EXPR, string_type, filename_string),
value);
- /* Workspace */
- value = tree_cons (NULL_TREE,
- convert (long_integer_type_node, integer_zero_node),
- value);
-
- /* number of functions */
- n_functions = 0;
- for (item = functions_head; item != 0; item = item->next, n_functions++)
- continue;
- value = tree_cons (NULL_TREE,
- convert (unsigned_type_node,
- build_int_2 (n_functions, 0)),
- value);
-
- /* function_info table */
- function_info_fields = build_function_info_fields ();
- function_info_type = (*lang_hooks.types.make_type) (RECORD_TYPE);
- function_info_ptr_type =
- build_pointer_type (
- build_qualified_type (function_info_type,
- TYPE_QUAL_CONST));
- functions = NULL_TREE;
- for (item = functions_head; item != 0; item = item->next)
- {
- tree function_info_value = build_function_info_value (item);
- set_purpose (function_info_value, function_info_fields);
- functions
- = tree_cons (NULL_TREE,
- build_constructor (function_info_type,
- nreverse (function_info_value)),
- functions);
- }
- finish_builtin_struct (function_info_type, "__function_info",
- function_info_fields, NULL_TREE);
-
- /* Create constructor for array. */
- if (n_functions)
+ /* 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++)
+ fn_info_value = tree_cons (NULL_TREE,
+ build_fn_info_value (fn, fn_info_type),
+ fn_info_value);
+ if (n_fns)
{
tree array_type;
- array_type = build_array_type (
- function_info_type,
- build_index_type (build_int_2 (n_functions - 1, 0)));
- functions = build_constructor (array_type, nreverse (functions));
- functions = build1 (ADDR_EXPR,
- function_info_ptr_type,
- functions);
+ array_type = build_index_type (build_int_2 (n_fns - 1, 0));
+ array_type = build_array_type (fn_info_type, array_type);
+
+ fn_info_value = build_constructor (array_type, nreverse (fn_info_value));
+ fn_info_value = build1 (ADDR_EXPR, fn_info_ptr_type, fn_info_value);
}
else
- functions = null_pointer_node;
-
- value = tree_cons (NULL_TREE, functions, value);
+ fn_info_value = null_pointer_node;
+
+ /* number of functions */
+ field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
+ TREE_CHAIN (field) = fields;
+ fields = field;
+ value = tree_cons (field,
+ convert (unsigned_type_node, build_int_2 (n_fns, 0)),
+ value);
+
+ /* fn_info table */
+ field = build_decl (FIELD_DECL, NULL_TREE, fn_info_ptr_type);
+ TREE_CHAIN (field) = fields;
+ fields = field;
+ value = tree_cons (field, fn_info_value, value);
- /* n_counter_sections */
- value = tree_cons (NULL_TREE,
+ /* counter_mask */
+ field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
+ TREE_CHAIN (field) = fields;
+ fields = field;
+ value = tree_cons (field,
convert (unsigned_type_node,
- build_int_2 (profile_info.n_sections, 0)),
+ build_int_2 (prg_ctr_mask, 0)),
value);
- /* counter sections */
- counter_section_data_fields = build_counter_section_data_fields ();
- counter_section_data_type = (*lang_hooks.types.make_type) (RECORD_TYPE);
- counter_sections = NULL_TREE;
- for (i = 0; i < profile_info.n_sections; i++)
- {
- tree counter_sections_value =
- build_counter_section_data_value (
- profile_info.section_info[i].tag,
- profile_info.section_info[i].n_counters);
- set_purpose (counter_sections_value, counter_section_data_fields);
- counter_sections =
- tree_cons (NULL_TREE,
- build_constructor (counter_section_data_type,
- nreverse (counter_sections_value)),
- counter_sections);
- }
- finish_builtin_struct (counter_section_data_type, "__counter_section_data",
- counter_section_data_fields, NULL_TREE);
- counter_section_data_ptr_type =
- build_pointer_type
- (build_qualified_type (counter_section_data_type,
- TYPE_QUAL_CONST));
-
- if (profile_info.n_sections)
- {
- tree cst_type = build_index_type (build_int_2 (profile_info.n_sections-1,
- 0));
- cst_type = build_array_type (counter_section_data_type, cst_type);
- counter_sections = build_constructor (cst_type,
- nreverse (counter_sections));
- counter_sections = build1 (ADDR_EXPR,
- counter_section_data_ptr_type,
- counter_sections);
- }
- else
- counter_sections = null_pointer_node;
- value = tree_cons (NULL_TREE, counter_sections, value);
+ /* counters */
+ ctr_info_type = build_ctr_info_type ();
+ ctr_info_ary_type = build_index_type (build_int_2 (n_ctr_types, 0));
+ ctr_info_ary_type = build_array_type (ctr_info_type, ctr_info_ary_type);
+ for (ix = 0; ix != GCOV_COUNTERS; ix++)
+ if (prg_ctr_mask & (1 << ix))
+ ctr_info_value = tree_cons (NULL_TREE,
+ build_ctr_info_value (ix, ctr_info_type),
+ ctr_info_value);
+ ctr_info_value = build_constructor (ctr_info_ary_type,
+ nreverse (ctr_info_value));
+
+ field = build_decl (FIELD_DECL, NULL_TREE, ctr_info_ary_type);
+ TREE_CHAIN (field) = fields;
+ fields = field;
+ value = tree_cons (field, ctr_info_value, value);
+
+ finish_builtin_struct (type, "__gcov_info", fields, NULL_TREE);
+ value = build_constructor (type, nreverse (value));
+
return value;
}
-/* Write out the structure which libgcc uses to locate all the arc
+/* Write out the structure which libgcov uses to locate all the
counters. The structures used here must match those defined in
gcov-io.h. Write out the constructor to call __gcov_init. */
static void
create_coverage ()
{
- tree gcov_info_fields, gcov_info_type, gcov_info_value, gcov_info;
+ tree gcov_info, gcov_info_value;
char name[20];
char *ctor_name;
tree ctor;
rtx gcov_info_address;
int save_flag_inline_functions = flag_inline_functions;
- unsigned i;
- for (i = 0; i < profile_info.n_sections; i++)
- if (profile_info.section_info[i].n_counters)
- break;
- if (i == profile_info.n_sections)
+ if (!prg_ctr_mask)
return;
- gcov_info_type = (*lang_hooks.types.make_type) (RECORD_TYPE);
- gcov_info_fields = build_gcov_info_fields (gcov_info_type);
- gcov_info_value = build_gcov_info_value ();
- set_purpose (gcov_info_value, gcov_info_fields);
- finish_builtin_struct (gcov_info_type, "__gcov_info",
- gcov_info_fields, NULL_TREE);
+ gcov_info_value = build_gcov_info ();
- gcov_info = build (VAR_DECL, gcov_info_type, NULL_TREE, NULL_TREE);
- DECL_INITIAL (gcov_info) =
- build_constructor (gcov_info_type, nreverse (gcov_info_value));
+ gcov_info = build (VAR_DECL, TREE_TYPE (gcov_info_value),
+ NULL_TREE, NULL_TREE);
+ DECL_INITIAL (gcov_info) = gcov_info_value;
TREE_STATIC (gcov_info) = 1;
ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 0);
@@ -1044,59 +845,6 @@ create_coverage ()
DEFAULT_INIT_PRIORITY);
}
-/* Find (and create if not present) a section with TAG for the current
- function. */
-struct section_info *
-find_counters_section (tag)
- unsigned tag;
-{
- unsigned i;
-
- for (i = 0; i < profile_info.n_sections; i++)
- if (profile_info.section_info[i].tag == tag)
- return profile_info.section_info + i;
-
- if (i == MAX_COUNTER_SECTIONS)
- abort ();
-
- profile_info.section_info[i].tag = tag;
- profile_info.section_info[i].present = 0;
- profile_info.section_info[i].n_counters = 0;
- profile_info.section_info[i].n_counters_now = 0;
- profile_info.n_sections++;
-
- return profile_info.section_info + i;
-}
-
-/* Generate a MEM rtl to access counter NO in counter section TAG. */
-
-rtx
-coverage_counter_ref (unsigned tag, unsigned no)
-{
- enum machine_mode mode = mode_for_size (GCOV_TYPE_SIZE, MODE_INT, 0);
- struct section_info *sect = find_counters_section (tag);
- rtx ref;
-
- if (!profiler_label)
- {
- /* Generate and save a copy of this so it can be shared. */
- char buf[20];
-
- ASM_GENERATE_INTERNAL_LABEL (buf, "LPBX", 2);
- profiler_label = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
- }
- if (no + 1 > (unsigned) sect->n_counters_now)
- sect->n_counters_now = no + 1;
-
- no += sect->n_counters;
- ref = plus_constant (profiler_label, GCOV_TYPE_SIZE / BITS_PER_UNIT * no);
- ref = gen_rtx_MEM (mode, ref);
- set_mem_alias_set (ref, new_alias_set ());
-
- return ref;
-}
-
-
/* Perform file-level initialization. Read in data file, generate name
of graph file. */
@@ -1142,5 +890,4 @@ coverage_finish ()
}
}
-
#include "gt-coverage.h"
diff --git a/gcc/coverage.h b/gcc/coverage.h
index f6ead44..8817b80 100644
--- a/gcc/coverage.h
+++ b/gcc/coverage.h
@@ -23,50 +23,14 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "gcov-io.h"
-/* The number of different counter sections. */
-#define MAX_COUNTER_SECTIONS 1
-
-/* Info about number of counters in the section. */
-struct section_info
-{
- unsigned tag; /* Section tag. */
- int present; /* Are the data from this section read into gcc? */
- int n_counters; /* Total number of counters. */
- int n_counters_now; /* Number of counters in the current function. */
-};
-
-struct profile_info
- {
- /* Information about numbers of counters in counter sections, for
- allocating the storage and storing the sizes. */
- unsigned n_sections;
- struct section_info section_info[MAX_COUNTER_SECTIONS];
-
- /* Checksum of the cfg. Used for 'identification' of code.
- Used by final. */
-
- unsigned current_function_cfg_checksum;
-
- /* Max. value of counter in program corresponding to the profile data
- for the current function. */
-
- gcov_type max_counter_in_program;
-
- /* The number of profiles merged to form the profile data for the current
- function. */
- int count_profiles_merged;
- };
-
-extern struct profile_info profile_info;
-
extern void coverage_init (const char *);
extern void coverage_finish (void);
extern void coverage_end_function (void);
extern int coverage_begin_output (void);
-extern rtx coverage_counter_ref (unsigned /*tag*/, unsigned/*num*/);
-
-gcov_type *get_coverage_counts (unsigned /*tag*/, unsigned /*expected*/);
-struct section_info *find_counters_section PARAMS ((unsigned));
+extern rtx coverage_counter_ref (unsigned /*counter*/, unsigned/*num*/);
+extern gcov_type *get_coverage_counts (unsigned /*counter*/,
+ unsigned /*expected*/,
+ const struct gcov_ctr_summary **);
#endif
diff --git a/gcc/gcov-dump.c b/gcc/gcov-dump.c
index fd9d122..5c0dd3a 100644
--- a/gcc/gcov-dump.c
+++ b/gcc/gcov-dump.c
@@ -35,7 +35,7 @@ static void tag_function PARAMS ((const char *, unsigned, unsigned));
static void tag_blocks PARAMS ((const char *, unsigned, unsigned));
static void tag_arcs PARAMS ((const char *, unsigned, unsigned));
static void tag_lines PARAMS ((const char *, unsigned, unsigned));
-static void tag_arc_counts PARAMS ((const char *, unsigned, unsigned));
+static void tag_counters PARAMS ((const char *, unsigned, unsigned));
static void tag_summary PARAMS ((const char *, unsigned, unsigned));
extern int main PARAMS ((int, char **));
@@ -59,15 +59,13 @@ static const tag_format_t tag_table[] =
{
{0, "NOP", NULL},
{0, "UNKNOWN", NULL},
+ {0, "COUNTERS", tag_counters},
{GCOV_TAG_FUNCTION, "FUNCTION", tag_function},
{GCOV_TAG_BLOCKS, "BLOCKS", tag_blocks},
{GCOV_TAG_ARCS, "ARCS", tag_arcs},
{GCOV_TAG_LINES, "LINES", tag_lines},
- {GCOV_TAG_ARC_COUNTS, "ARC_COUNTS", tag_arc_counts},
{GCOV_TAG_OBJECT_SUMMARY, "OBJECT_SUMMARY", tag_summary},
{GCOV_TAG_PROGRAM_SUMMARY, "PROGRAM_SUMMARY", tag_summary},
- {GCOV_TAG_PLACEHOLDER_SUMMARY, "PROGRAM_PLACEHOLDER", tag_summary},
- {GCOV_TAG_INCORRECT_SUMMARY, "PROGRAM_INCORRECT", tag_summary},
{0, NULL, NULL}
};
@@ -208,7 +206,7 @@ dump_file (filename)
for (format = tag_table; format->name; format++)
if (format->tag == tag)
goto found;
- format = &tag_table[1];
+ format = &tag_table[GCOV_TAG_IS_COUNTER (tag) ? 2 : 1];
found:;
if (tag)
{
@@ -364,14 +362,16 @@ tag_lines (filename, tag, length)
}
static void
-tag_arc_counts (filename, tag, length)
+tag_counters (filename, tag, length)
const char *filename ATTRIBUTE_UNUSED;
unsigned tag ATTRIBUTE_UNUSED;
unsigned length ATTRIBUTE_UNUSED;
{
+ static const char *const counter_names[] = GCOV_COUNTER_NAMES;
unsigned n_counts = length / 8;
- printf (" %u counts", n_counts);
+ printf (" %s %u counts",
+ counter_names[GCOV_COUNTER_FOR_TAG (tag)], n_counts);
if (flag_dump_contents)
{
unsigned ix;
@@ -395,20 +395,21 @@ tag_summary (filename, tag, length)
unsigned length ATTRIBUTE_UNUSED;
{
struct gcov_summary summary;
-
- gcov_read_summary (&summary);
+ unsigned ix;
+ gcov_read_summary (&summary);
printf (" checksum=0x%08x", summary.checksum);
- printf ("\n%s:\t\truns=%u, arcs=%u", filename,
- summary.runs, summary.arcs);
- printf ("\n%s:\t\tarc_sum=", filename);
- printf (HOST_WIDEST_INT_PRINT_DEC,
- (HOST_WIDEST_INT)summary.arc_sum);
- printf (", arc_max_one=");
- printf (HOST_WIDEST_INT_PRINT_DEC,
- (HOST_WIDEST_INT)summary.arc_max_one);
- printf (", sum_max=");
- printf (HOST_WIDEST_INT_PRINT_DEC,
- (HOST_WIDEST_INT)summary.arc_sum_max);
+ for (ix = 0; ix != GCOV_COUNTERS; ix++)
+ {
+ printf ("\n%sL\t\tcounts=%u, runs=%u", filename,
+ summary.ctrs[ix].num, summary.ctrs[ix].runs);
+
+ printf (", sum_all=" HOST_WIDEST_INT_PRINT_DEC,
+ (HOST_WIDEST_INT)summary.ctrs[ix].sum_all);
+ printf (", run_max=" HOST_WIDEST_INT_PRINT_DEC,
+ (HOST_WIDEST_INT)summary.ctrs[ix].run_max);
+ printf (", sum_max=" HOST_WIDEST_INT_PRINT_DEC,
+ (HOST_WIDEST_INT)summary.ctrs[ix].sum_max);
+ }
}
diff --git a/gcc/gcov-io.c b/gcc/gcov-io.c
index 94002a9..b595217 100644
--- a/gcc/gcov-io.c
+++ b/gcc/gcov-io.c
@@ -305,15 +305,20 @@ gcov_write_length (unsigned long position)
GCOV_LINKAGE void
gcov_write_summary (unsigned tag, const struct gcov_summary *summary)
{
+ unsigned ix;
+ const struct gcov_ctr_summary *csum;
unsigned long base;
base = gcov_write_tag (tag);
gcov_write_unsigned (summary->checksum);
- gcov_write_unsigned (summary->runs);
- gcov_write_unsigned (summary->arcs);
- gcov_write_counter (summary->arc_sum);
- gcov_write_counter (summary->arc_max_one);
- gcov_write_counter (summary->arc_sum_max);
+ for (csum = summary->ctrs, ix = GCOV_COUNTERS; ix--; csum++)
+ {
+ gcov_write_unsigned (csum->num);
+ gcov_write_unsigned (csum->runs);
+ gcov_write_counter (csum->sum_all);
+ gcov_write_counter (csum->run_max);
+ gcov_write_counter (csum->sum_max);
+ }
gcov_write_length (base);
}
#endif /* IN_LIBGCOV */
@@ -406,15 +411,20 @@ gcov_read_string ()
GCOV_LINKAGE void
gcov_read_summary (struct gcov_summary *summary)
{
+ unsigned ix;
+ struct gcov_ctr_summary *csum;
+
summary->checksum = gcov_read_unsigned ();
- summary->runs = gcov_read_unsigned ();
- summary->arcs = gcov_read_unsigned ();
- summary->arc_sum = gcov_read_counter ();
- summary->arc_max_one = gcov_read_counter ();
- summary->arc_sum_max = gcov_read_counter ();
+ for (csum = summary->ctrs, ix = GCOV_COUNTERS; ix--; csum++)
+ {
+ csum->num = gcov_read_unsigned ();
+ csum->runs = gcov_read_unsigned ();
+ csum->sum_all = gcov_read_counter ();
+ csum->run_max = gcov_read_counter ();
+ csum->sum_max = gcov_read_counter ();
+ }
}
-
#if IN_GCOV > 0
/* Return the modification time of the current gcov file. */
diff --git a/gcc/gcov-io.h b/gcc/gcov-io.h
index d2beb1b..7f88199 100644
--- a/gcc/gcov-io.h
+++ b/gcc/gcov-io.h
@@ -127,8 +127,9 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
function-data: announce_function arc_counts
announce_function: header string:name int32:checksum
arc_counts: header int64:count*
- summary: in32:checksum int32:runs int32:arcs int64:sum int64:max \
- int64:sum_max
+ summary: int32:checksum {count-summary}GCOV_COUNTERS
+ count-summary: int32:num int32:runs int64:sum
+ int64:max int64:sum_max
The ANNOUNCE_FUNCTION record is the same as that in the BBG file,
but without the source location.
@@ -160,6 +161,11 @@ typedef long gcov_type;
#else
typedef long long gcov_type;
#endif
+#if defined (TARGET_HAS_F_SETLKW)
+#define GCOV_LOCKED 1
+#else
+#define GCOV_LOCKED 0
+#endif
#endif /* IN_LIBGCOV */
#if IN_GCOV
typedef HOST_WIDEST_INT gcov_type;
@@ -201,11 +207,26 @@ typedef HOST_WIDEST_INT gcov_type;
#define GCOV_TAG_BLOCKS ((unsigned)0x01410000)
#define GCOV_TAG_ARCS ((unsigned)0x01430000)
#define GCOV_TAG_LINES ((unsigned)0x01450000)
-#define GCOV_TAG_ARC_COUNTS ((unsigned)0x01a10000)
+#define GCOV_TAG_COUNTER_BASE ((unsigned)0x01a10000) /* First counter */
#define GCOV_TAG_OBJECT_SUMMARY ((unsigned)0xa1000000)
#define GCOV_TAG_PROGRAM_SUMMARY ((unsigned)0xa3000000)
-#define GCOV_TAG_PLACEHOLDER_SUMMARY ((unsigned)0xa5000000)
-#define GCOV_TAG_INCORRECT_SUMMARY ((unsigned)0xa7000000)
+
+/* Counters that are collected. */
+#define GCOV_COUNTER_ARCS 0 /* Arc transitions. */
+#define GCOV_COUNTERS 1
+
+/* A list of human readable names of the counters */
+#define GCOV_COUNTER_NAMES {"arcs"}
+
+/* Convert a counter index to a tag. */
+#define GCOV_TAG_FOR_COUNTER(COUNT) \
+ (GCOV_TAG_COUNTER_BASE + ((COUNT) << 17))
+/* Convert a tag to a counter. */
+#define GCOV_COUNTER_FOR_TAG(TAG) \
+ (((TAG) - GCOV_TAG_COUNTER_BASE) >> 17)
+/* Check whether a tag is a counter tag. */
+#define GCOV_TAG_IS_COUNTER(TAG) \
+ (!((TAG) & 0xFFFF) && GCOV_COUNTER_FOR_TAG (TAG) < GCOV_COUNTERS)
/* The tag level mask has 1's in the position of the inner levels, &
the lsb of the current level, and zero on the current and outer
@@ -231,44 +252,43 @@ typedef HOST_WIDEST_INT gcov_type;
/* Structured records. */
+/* Cumulative counter data. */
+struct gcov_ctr_summary
+{
+ unsigned num; /* number of counters. */
+ unsigned runs; /* number of program runs */
+ gcov_type sum_all; /* sum of all counters accumulated. */
+ gcov_type run_max; /* maximum value on a single run. */
+ gcov_type sum_max; /* sum of individual run max values. */
+};
+
/* Object & program summary record. */
struct gcov_summary
{
unsigned checksum; /* checksum of program */
- unsigned runs; /* number of program runs */
- unsigned arcs; /* number of instrumented arcs */
- gcov_type arc_sum; /* sum of all arc counters */
- gcov_type arc_max_one; /* max counter on any one run */
- gcov_type arc_sum_max; /* sum of max_one */
+ struct gcov_ctr_summary ctrs[GCOV_COUNTERS];
};
/* Structures embedded in coveraged program. The structures generated
by write_profile must match these. */
-/* Information about section of counters for a function. */
-struct gcov_counter_section
-{
- unsigned tag; /* Tag of the section. */
- unsigned n_counters; /* Number of counters in the section. */
-};
-
#if IN_LIBGCOV
-/* Information about section of counters for an object file. */
-struct gcov_counter_section_data
+/* 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
{
- unsigned tag; /* Tag of the section. */
- unsigned n_counters; /* Number of counters in the section. */
- gcov_type *counters; /* The data. */
+ const char *name; /* (mangled) name of function */
+ unsigned checksum; /* function checksum */
+ unsigned n_ctrs[0]; /* instrumented counters */
};
-/* Information about a single function. */
-struct gcov_function_info
+/* Information about counters. */
+struct gcov_ctr_info
{
- const char *name; /* (mangled) name of function */
- unsigned checksum; /* function checksum */
- unsigned n_counter_sections; /* Number of types of counters */
- const struct gcov_counter_section *counter_sections;
- /* The section descriptions */
+ unsigned num; /* number of counters. */
+ gcov_type *values; /* their values. */
};
/* Information about a single object file. */
@@ -278,14 +298,15 @@ struct gcov_info
struct gcov_info *next; /* link to next, used by libgcc */
const char *filename; /* output file name */
- long wkspc; /* libgcc workspace */
unsigned n_functions; /* number of functions */
- const struct gcov_function_info *functions; /* table of functions */
+ const struct gcov_fn_info *functions; /* table of functions */
- unsigned n_counter_sections; /* Number of types of counters */
- const struct gcov_counter_section_data *counter_sections;
- /* The data to be put into the sections. */
+ 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. */
};
/* Register a new object file module. */
diff --git a/gcc/gcov.c b/gcc/gcov.c
index 8a41367..5722923 100644
--- a/gcc/gcov.c
+++ b/gcc/gcov.c
@@ -1011,8 +1011,7 @@ read_count_file ()
if (tag == GCOV_TAG_OBJECT_SUMMARY)
gcov_read_summary (&object_summary);
- else if (tag == GCOV_TAG_PROGRAM_SUMMARY
- || tag == GCOV_TAG_INCORRECT_SUMMARY)
+ else if (tag == GCOV_TAG_PROGRAM_SUMMARY)
program_count++;
else if (tag == GCOV_TAG_FUNCTION)
{
@@ -1045,7 +1044,7 @@ read_count_file ()
goto cleanup;
}
}
- else if (tag == GCOV_TAG_ARC_COUNTS && fn)
+ else if (tag == GCOV_TAG_FOR_COUNTER (GCOV_COUNTER_ARCS) && fn)
{
if (length != 8 * fn->num_counts)
goto mismatch;
@@ -1801,7 +1800,8 @@ output_lines (gcov_file, src)
fprintf (gcov_file, "%9s:%5d:Source:%s\n", "-", 0, src->name);
fprintf (gcov_file, "%9s:%5d:Graph:%s\n", "-", 0, bbg_file_name);
fprintf (gcov_file, "%9s:%5d:Data:%s\n", "-", 0, da_file_name);
- fprintf (gcov_file, "%9s:%5d:Runs:%u\n", "-", 0, object_summary.runs);
+ fprintf (gcov_file, "%9s:%5d:Runs:%u\n", "-", 0,
+ object_summary.ctrs[GCOV_COUNTER_ARCS].runs);
fprintf (gcov_file, "%9s:%5d:Programs:%u\n", "-", 0, program_count);
source_file = fopen (src->name, "r");
diff --git a/gcc/libgcov.c b/gcc/libgcov.c
index 237da2d..a2c831e 100644
--- a/gcc/libgcov.c
+++ b/gcc/libgcov.c
@@ -96,93 +96,91 @@ gcov_version_mismatch (struct gcov_info *ptr, unsigned version)
static void
gcov_exit (void)
{
- struct gcov_info *ptr;
- unsigned ix, jx;
- gcov_type program_max_one = 0;
- gcov_type program_sum = 0;
- unsigned program_arcs = 0;
- struct gcov_summary last_prg;
-
- last_prg.runs = 0;
-
- for (ptr = gcov_list; ptr; ptr = ptr->next)
+ struct gcov_info *gi_ptr;
+ struct gcov_summary this_program;
+ struct gcov_summary all;
+
+ memset (&all, 0, sizeof (all));
+ /* Find the totals for this execution. */
+ memset (&this_program, 0, sizeof (this_program));
+ for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
{
- unsigned arc_data_index;
- gcov_type *count_ptr;
-
- if (!ptr->filename)
- continue;
-
- for (arc_data_index = 0;
- arc_data_index < ptr->n_counter_sections
- && ptr->counter_sections[arc_data_index].tag != GCOV_TAG_ARC_COUNTS;
- arc_data_index++)
- continue;
-
- for (ix = ptr->counter_sections[arc_data_index].n_counters,
- count_ptr = ptr->counter_sections[arc_data_index].counters; ix--;)
- {
- gcov_type count = *count_ptr++;
-
- if (count > program_max_one)
- program_max_one = count;
- program_sum += count;
- }
- program_arcs += ptr->counter_sections[arc_data_index].n_counters;
+ const struct gcov_ctr_info *ci_ptr;
+ struct gcov_ctr_summary *cs_ptr;
+ unsigned t_ix;
+
+ for (t_ix = 0, ci_ptr = gi_ptr->counts, cs_ptr = this_program.ctrs;
+ t_ix != GCOV_COUNTERS; t_ix++, cs_ptr++)
+ if ((1 << t_ix) & gi_ptr->ctr_mask)
+ {
+ const gcov_type *c_ptr;
+ unsigned c_num;
+
+ cs_ptr->num += ci_ptr->num;
+ for (c_num = ci_ptr->num, c_ptr = ci_ptr->values; c_num--; c_ptr++)
+ {
+ cs_ptr->sum_all += *c_ptr;
+ if (cs_ptr->run_max < *c_ptr)
+ cs_ptr->run_max = *c_ptr;
+ }
+ ci_ptr++;
+ }
}
- for (ptr = gcov_list; ptr; ptr = ptr->next)
+
+ /* Now write the data */
+ for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
{
- struct gcov_summary object;
- struct gcov_summary local_prg;
+ 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, t_ix, f_ix;
+ const struct gcov_ctr_info *ci_ptr;
+ struct gcov_ctr_summary *cs_ptr;
+ struct gcov_ctr_summary *cs_obj, *cs_tobj, *cs_prg, *cs_tprg, *cs_all;
int error;
int merging;
unsigned long base;
- const struct gcov_function_info *fn_info;
- gcov_type **counters;
- gcov_type *count_ptr;
- gcov_type object_max_one = 0;
unsigned tag, length;
- unsigned arc_data_index, f_sect_index, sect_index;
- long summary_pos = 0;
-
- if (!ptr->filename)
- continue;
-
- counters = malloc (sizeof (gcov_type *) * ptr->n_counter_sections);
- for (ix = 0; ix < ptr->n_counter_sections; ix++)
- counters[ix] = ptr->counter_sections[ix].counters;
-
- for (arc_data_index = 0;
- arc_data_index < ptr->n_counter_sections
- && ptr->counter_sections[arc_data_index].tag != GCOV_TAG_ARC_COUNTS;
- arc_data_index++)
- continue;
-
- if (arc_data_index == ptr->n_counter_sections)
+ unsigned long summary_pos = 0;
+
+ /* Totals for this object file. */
+ memset (&this_object, 0, sizeof (this_object));
+ for (t_ix = c_ix = 0,
+ ci_ptr = gi_ptr->counts, cs_ptr = this_object.ctrs;
+ t_ix != GCOV_COUNTERS; t_ix++, cs_ptr++)
+ if ((1 << t_ix) & gi_ptr->ctr_mask)
+ {
+ const gcov_type *c_ptr;
+ unsigned c_num;
+
+ cs_ptr->num += ci_ptr->num;
+ values[c_ix] = ci_ptr->values;
+ for (c_num = ci_ptr->num, c_ptr = ci_ptr->values; c_num--; c_ptr++)
+ {
+ cs_ptr->sum_all += *c_ptr;
+ if (cs_ptr->run_max < *c_ptr)
+ cs_ptr->run_max = *c_ptr;
+ }
+ c_ix++;
+ ci_ptr++;
+ }
+
+ /* 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))
{
- /* For now; later we may want to just measure other profiles,
- but now I am lazy to check for all consequences. */
- abort ();
+ fi_stride += __alignof__ (struct gcov_fn_info) - 1;
+ fi_stride &= ~(__alignof__ (struct gcov_fn_info) - 1);
}
- for (ix = ptr->counter_sections[arc_data_index].n_counters,
- count_ptr = ptr->counter_sections[arc_data_index].counters; ix--;)
- {
- gcov_type count = *count_ptr++;
-
- if (count > object_max_one)
- object_max_one = count;
- }
-
- memset (&local_prg, 0, sizeof (local_prg));
- memset (&object, 0, sizeof (object));
-
- /* Open for modification */
- merging = gcov_open (ptr->filename, 0);
+ /* Open for modification, if possible */
+ merging = gcov_open (gi_ptr->filename, 0);
if (!merging)
{
- fprintf (stderr, "profiling:%s:Cannot open\n", ptr->filename);
- ptr->filename = 0;
+ fprintf (stderr, "profiling:%s:Cannot open\n", gi_ptr->filename);
continue;
}
@@ -192,22 +190,22 @@ gcov_exit (void)
if (gcov_read_unsigned () != GCOV_DATA_MAGIC)
{
fprintf (stderr, "profiling:%s:Not a gcov data file\n",
- ptr->filename);
+ gi_ptr->filename);
read_fatal:;
gcov_close ();
- ptr->filename = 0;
continue;
}
length = gcov_read_unsigned ();
if (length != GCOV_VERSION)
{
- gcov_version_mismatch (ptr, length);
+ gcov_version_mismatch (gi_ptr, length);
goto read_fatal;
}
/* Merge execution counts for each function. */
- for (ix = ptr->n_functions, fn_info = ptr->functions;
- ix--; fn_info++)
+ for (f_ix = gi_ptr->n_functions, fi_ptr = gi_ptr->functions; f_ix--;
+ fi_ptr = (const struct gcov_fn_info *)
+ ((const char *) fi_ptr + fi_stride))
{
tag = gcov_read_unsigned ();
length = gcov_read_unsigned ();
@@ -216,42 +214,34 @@ gcov_exit (void)
if (tag != GCOV_TAG_FUNCTION)
{
read_mismatch:;
- fprintf (stderr, "profiling:%s:Merge mismatch at %s\n",
- ptr->filename, fn_info->name);
+ fprintf (stderr, "profiling:%s:Merge mismatch for %s\n",
+ gi_ptr->filename,
+ fi_ptr ? fi_ptr->name : "summaries");
goto read_fatal;
}
- if (strcmp (gcov_read_string (), fn_info->name)
- || gcov_read_unsigned () != fn_info->checksum)
+ if (strcmp (gcov_read_string (), fi_ptr->name)
+ || gcov_read_unsigned () != fi_ptr->checksum)
goto read_mismatch;
- /* Counters. */
- for (f_sect_index = 0;
- f_sect_index < fn_info->n_counter_sections;
- f_sect_index++)
- {
- unsigned n_counters;
-
- tag = gcov_read_unsigned ();
- length = gcov_read_unsigned ();
-
- for (sect_index = 0;
- sect_index < ptr->n_counter_sections;
- sect_index++)
- if (ptr->counter_sections[sect_index].tag == tag)
- break;
- if (sect_index == ptr->n_counter_sections
- || fn_info->counter_sections[f_sect_index].tag != tag)
- goto read_mismatch;
-
- n_counters = fn_info->counter_sections[f_sect_index].n_counters;
- if (n_counters != length / 8)
- goto read_mismatch;
-
- for (jx = 0; jx < n_counters; jx++)
- counters[sect_index][jx] += gcov_read_counter ();
-
- counters[sect_index] += n_counters;
+ for (c_ix = t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
+ if ((1 << t_ix) & gi_ptr->ctr_mask)
+ {
+ unsigned n_counts;
+ gcov_type *c_ptr;
+
+ tag = gcov_read_unsigned ();
+ length = gcov_read_unsigned ();
+
+ if (tag != GCOV_TAG_FOR_COUNTER (t_ix)
+ || fi_ptr->n_ctrs[c_ix] * 8 != length)
+ goto read_mismatch;
+ c_ptr = values[c_ix];
+ for (n_counts = fi_ptr->n_ctrs[c_ix];
+ n_counts--; c_ptr++)
+ *c_ptr += gcov_read_counter ();
+ values[c_ix] = c_ptr;
+ c_ix++;
}
if ((error = gcov_is_error ()))
goto read_error;
@@ -266,148 +256,134 @@ gcov_exit (void)
/* Check program summary */
while (!gcov_is_eof ())
{
- unsigned long base = gcov_position ();
-
+ base = gcov_position ();
tag = gcov_read_unsigned ();
gcov_read_unsigned ();
if (tag != GCOV_TAG_PROGRAM_SUMMARY)
goto read_mismatch;
- gcov_read_summary (&local_prg);
+ gcov_read_summary (&program);
if ((error = gcov_is_error ()))
{
read_error:;
fprintf (stderr, error < 0 ?
"profiling:%s:Overflow merging\n" :
"profiling:%s:Error merging\n",
- ptr->filename);
+ gi_ptr->filename);
goto read_fatal;
}
- if (local_prg.checksum != gcov_crc32)
- {
- memset (&local_prg, 0, sizeof (local_prg));
- continue;
- }
- merging = 0;
- if (tag != GCOV_TAG_PROGRAM_SUMMARY)
- break;
-
- /* If everything done correctly, the summaries should be
- computed equal for each module. */
- if (last_prg.runs
-#ifdef TARGET_HAS_F_SETLKW
- && last_prg.runs == local_prg.runs
-#endif
- && memcmp (&last_prg, &local_prg, sizeof (last_prg)))
- {
-#ifdef TARGET_HAS_F_SETLKW
- fprintf (stderr, "profiling:%s:Invocation mismatch\n\
-Probably some files were removed\n",
- ptr->filename);
-#else
- fprintf (stderr, "profiling:%s:Invocation mismatch\n\
-Probably some files were removed or parallel race happent because libgcc\n\
-is compiled without file locking support.\n",
- ptr->filename);
-#endif
- local_prg.runs = 0;
- }
- else
- memcpy (&last_prg, &local_prg, sizeof (last_prg));
+ if (program.checksum != gcov_crc32)
+ continue;
summary_pos = base;
break;
}
gcov_seek (0, 0);
}
+ else
+ memset (&object, 0, sizeof (object));
+ if (!summary_pos)
+ memset (&program, 0, sizeof (program));
- object.runs++;
- object.arcs = ptr->counter_sections[arc_data_index].n_counters;
- object.arc_sum = 0;
- if (object.arc_max_one < object_max_one)
- object.arc_max_one = object_max_one;
- object.arc_sum_max += object_max_one;
+ fi_ptr = 0;
+
+ /* Merge the summaries. */
+ for (t_ix = c_ix = 0,
+ cs_obj = object.ctrs, cs_tobj = this_object.ctrs,
+ cs_prg = program.ctrs, cs_tprg = this_program.ctrs,
+ cs_all = all.ctrs;
+ t_ix != GCOV_COUNTERS;
+ t_ix++, cs_obj++, cs_tobj++, cs_prg++, cs_tprg++, cs_all++)
+ {
+ if ((1 << t_ix) & gi_ptr->ctr_mask)
+ {
+ 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)
+ goto read_mismatch;
+ cs_prg->sum_all += cs_tprg->sum_all;
+ if (cs_prg->run_max < cs_tprg->run_max)
+ cs_prg->run_max = cs_tprg->run_max;
+ cs_prg->sum_max += cs_tprg->run_max;
+
+ values[c_ix] = gi_ptr->counts[c_ix].values;
+ c_ix++;
+ }
+ else if (cs_obj->num || cs_prg->num)
+ goto read_mismatch;
+
+ if (!cs_all->runs && cs_prg->runs)
+ memcpy (cs_all, cs_prg, sizeof (*cs_all));
+ else if (!all.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",
+ gi_ptr->filename, GCOV_LOCKED
+ ? "" : " or concurrent update without locking support");
+ all.checksum = ~0u;
+ }
+ }
+
+ program.checksum = gcov_crc32;
/* Write out the data. */
gcov_write_unsigned (GCOV_DATA_MAGIC);
gcov_write_unsigned (GCOV_VERSION);
/* Write execution counts for each function. */
- for (ix = 0; ix < ptr->n_counter_sections; ix++)
- counters[ix] = ptr->counter_sections[ix].counters;
- for (ix = ptr->n_functions, fn_info = ptr->functions; ix--; fn_info++)
+ for (f_ix = gi_ptr->n_functions, fi_ptr = gi_ptr->functions; f_ix--;
+ fi_ptr = (const struct gcov_fn_info *)
+ ((const char *) fi_ptr + fi_stride))
{
/* Announce function. */
base = gcov_write_tag (GCOV_TAG_FUNCTION);
- gcov_write_string (fn_info->name);
- gcov_write_unsigned (fn_info->checksum);
+ gcov_write_string (fi_ptr->name);
+ gcov_write_unsigned (fi_ptr->checksum);
gcov_write_length (base);
- /* counters. */
- for (f_sect_index = 0;
- f_sect_index < fn_info->n_counter_sections;
- f_sect_index++)
- {
- tag = fn_info->counter_sections[f_sect_index].tag;
- for (sect_index = 0;
- sect_index < ptr->n_counter_sections;
- sect_index++)
- if (ptr->counter_sections[sect_index].tag == tag)
- break;
- if (sect_index == ptr->n_counter_sections)
- abort ();
-
- base = gcov_write_tag (tag);
- for (jx = fn_info->counter_sections[f_sect_index].n_counters; jx--;)
- {
- gcov_type count = *counters[sect_index]++;
-
- if (tag == GCOV_TAG_ARC_COUNTS)
- {
- object.arc_sum += count;
- }
- gcov_write_counter (count);
- }
- gcov_write_length (base);
- }
+ for (c_ix = t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
+ if ((1 << t_ix) & gi_ptr->ctr_mask)
+ {
+ unsigned n_counts;
+ gcov_type *c_ptr;
+
+ base = gcov_write_tag (GCOV_TAG_FOR_COUNTER (t_ix));
+ c_ptr = values[c_ix];
+ for (n_counts = fi_ptr->n_ctrs[c_ix]; n_counts--; c_ptr++)
+ gcov_write_counter (*c_ptr);
+ values[c_ix] = c_ptr;
+ gcov_write_length (base);
+ c_ix++;
+ }
}
/* Object file summary. */
gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, &object);
/* Generate whole program statistics. */
- local_prg.runs++;
- local_prg.checksum = gcov_crc32;
- local_prg.arcs = program_arcs;
- local_prg.arc_sum += program_sum;
- if (local_prg.arc_max_one < program_max_one)
- local_prg.arc_max_one = program_max_one;
- local_prg.arc_sum_max += program_max_one;
-
- if (merging)
- {
- gcov_seek_end ();
- gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &local_prg);
- }
- else if (summary_pos)
- {
- /* Zap trailing program summary */
- gcov_seek (summary_pos, 0);
- if (!local_prg.runs)
- ptr->wkspc = 0;
- gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &local_prg);
- }
- if (gcov_close ())
+ if (summary_pos)
+ gcov_seek (summary_pos, 0);
+ else
+ gcov_seek_end ();
+ gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &program);
+ if ((error = gcov_close ()))
{
- fprintf (stderr, "profiling:%s:Error writing\n", ptr->filename);
- ptr->filename = 0;
+ fprintf (stderr, error < 0 ?
+ "profiling:%s:Overflow writing\n" :
+ "profiling:%s:Error writing\n",
+ gi_ptr->filename);
+ gi_ptr->filename = 0;
}
}
- /* All statistic we gather can be done in one pass trought the file.
- Originally we did two - one for counts and other for the statistics. This
- brings problem with the file locking interface, but it is possible to
- implement so if need appears in the future - first pass updates local
- statistics and number of runs. Second pass then overwrite global
- statistics only when number of runs match. */
}
/* Add a new object file onto the bb chain. Invoked automatically
@@ -459,16 +435,20 @@ __gcov_init (struct gcov_info *info)
void
__gcov_flush (void)
{
- struct gcov_info *ptr;
+ const struct gcov_info *gi_ptr;
gcov_exit ();
- for (ptr = gcov_list; ptr; ptr = ptr->next)
+ for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
{
- unsigned i, j;
+ unsigned t_ix;
+ const struct gcov_ctr_info *ci_ptr;
- for (j = 0; j < ptr->n_counter_sections; j++)
- for (i = ptr->counter_sections[j].n_counters; i--;)
- ptr->counter_sections[j].counters[i] = 0;
+ 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++;
+ }
}
}
diff --git a/gcc/mklibgcc.in b/gcc/mklibgcc.in
index 7407851..9cf67cc 100644
--- a/gcc/mklibgcc.in
+++ b/gcc/mklibgcc.in
@@ -75,7 +75,7 @@ make_compile='$(MAKE) GCC_FOR_TARGET="$(GCC_FOR_TARGET)" \
libgcc2_c_dep='stmp-dirs $(srcdir)/libgcc2.c $(CONFIG_H) coretypes.h $(TM_H) $(MACHMODE_H) longlong.h gbl-ctors.h config.status stmp-int-hdrs tsystem.h'" $LIB2ADDEHDEP"
# Dependencies for libgcov.c
-libgcov_c_dep='stmp-dirs $(srcdir)/libgcov.c $(CONFIG_H) coretypes.h $(TM_H) $(MACHMODE_H) longlong.h gbl-ctors.h config.status stmp-int-hdrs tsystem.h'
+libgcov_c_dep='stmp-dirs $(srcdir)/libgcov.c $(CONFIG_H) coretypes.h $(TM_H) $(MACHMODE_H) longlong.h gbl-ctors.h config.status stmp-int-hdrs tsystem.h gcov-io.h gcov-io.c gcov-iov.h'
# Dependencies for fp-bit.c
fpbit_c_dep='stmp-dirs config.status tsystem.h'
diff --git a/gcc/predict.c b/gcc/predict.c
index 9bc7751..80ad41e 100644
--- a/gcc/predict.c
+++ b/gcc/predict.c
@@ -120,11 +120,9 @@ bool
maybe_hot_bb_p (bb)
basic_block bb;
{
- if (profile_info.count_profiles_merged
- && flag_branch_probabilities
+ if (profile_info && flag_branch_probabilities
&& (bb->count
- < profile_info.max_counter_in_program
- / PARAM_VALUE (HOT_BB_COUNT_FRACTION)))
+ < profile_info->sum_max / PARAM_VALUE (HOT_BB_COUNT_FRACTION)))
return false;
if (bb->frequency < BB_FREQ_MAX / PARAM_VALUE (HOT_BB_FREQUENCY_FRACTION))
return false;
@@ -137,11 +135,9 @@ bool
probably_cold_bb_p (bb)
basic_block bb;
{
- if (profile_info.count_profiles_merged
- && flag_branch_probabilities
+ if (profile_info && flag_branch_probabilities
&& (bb->count
- < profile_info.max_counter_in_program
- / PARAM_VALUE (HOT_BB_COUNT_FRACTION)))
+ < profile_info->sum_max / PARAM_VALUE (HOT_BB_COUNT_FRACTION)))
return true;
if (bb->frequency < BB_FREQ_MAX / PARAM_VALUE (HOT_BB_FREQUENCY_FRACTION))
return true;
@@ -153,10 +149,8 @@ bool
probably_never_executed_bb_p (bb)
basic_block bb;
{
- if (profile_info.count_profiles_merged
- && flag_branch_probabilities)
- return ((bb->count + profile_info.count_profiles_merged / 2)
- / profile_info.count_profiles_merged) == 0;
+ if (profile_info && flag_branch_probabilities)
+ return ((bb->count + profile_info->runs / 2) / profile_info->runs) == 0;
return false;
}
@@ -1266,8 +1260,7 @@ compute_function_frequency ()
{
basic_block bb;
- if (!profile_info.count_profiles_merged
- || !flag_branch_probabilities)
+ if (!profile_info || !flag_branch_probabilities)
return;
cfun->function_frequency = FUNCTION_FREQUENCY_UNLIKELY_EXECUTED;
FOR_EACH_BB (bb)
diff --git a/gcc/profile.c b/gcc/profile.c
index 3472bd0..6a5548b 100644
--- a/gcc/profile.c
+++ b/gcc/profile.c
@@ -81,26 +81,6 @@ struct bb_info {
gcov_type pred_count;
};
-/* Counts information for a function. */
-typedef struct counts_entry
-{
- /* We hash by */
- char *function_name;
- unsigned section;
-
- /* Store */
- unsigned checksum;
- unsigned n_counts;
- gcov_type *counts;
- unsigned merged;
- gcov_type max_counter;
- gcov_type max_counter_sum;
-
- /* Workspace */
- struct counts_entry *chain;
-
-} counts_entry_t;
-
#define EDGE_INFO(e) ((struct edge_info *) (e)->aux)
#define BB_INFO(b) ((struct bb_info *) (b)->aux)
@@ -110,6 +90,10 @@ typedef struct counts_entry
: ((bb) == EXIT_BLOCK_PTR \
? last_basic_block + 1 : (bb)->index + 1))
+/* Counter summary from the last set of coverage counts read. */
+
+const struct gcov_ctr_summary *profile_info;
+
/* Collect statistics on the performance of this pass for the entire source
file. */
@@ -195,16 +179,13 @@ get_exec_counts ()
num_edges++;
}
- counts = get_coverage_counts (GCOV_TAG_ARC_COUNTS, num_edges);
+ counts = get_coverage_counts (GCOV_COUNTER_ARCS, num_edges, &profile_info);
if (!counts)
return NULL;
- if (rtl_dump_file)
- {
- fprintf(rtl_dump_file, "Merged %i profiles with maximal count %i.\n",
- profile_info.count_profiles_merged,
- (int)profile_info.max_counter_in_program);
- }
+ if (rtl_dump_file && profile_info)
+ fprintf(rtl_dump_file, "Merged %u profiles with maximal count %u.\n",
+ profile_info->runs, (unsigned) profile_info->sum_max);
return counts;
}
@@ -547,7 +528,6 @@ compute_branch_probabilities ()
}
free_aux_for_blocks ();
- find_counters_section (GCOV_TAG_ARC_COUNTS)->present = 1;
}
/* Instrument and/or analyze program behavior based on program flow graph.
@@ -1013,7 +993,7 @@ static rtx
gen_edge_profiler (edgeno)
int edgeno;
{
- rtx ref = coverage_counter_ref (GCOV_TAG_ARC_COUNTS, edgeno);
+ rtx ref = coverage_counter_ref (GCOV_COUNTER_ARCS, edgeno);
rtx tmp;
enum machine_mode mode = GET_MODE (ref);
rtx sequence;
diff --git a/gcc/tracer.c b/gcc/tracer.c
index 1448670..701c16a 100644
--- a/gcc/tracer.c
+++ b/gcc/tracer.c
@@ -211,7 +211,7 @@ tail_duplicate ()
int max_dup_insns;
basic_block bb;
- if (profile_info.count_profiles_merged && flag_branch_probabilities)
+ if (profile_info && flag_branch_probabilities)
probability_cutoff = PARAM_VALUE (TRACER_MIN_BRANCH_PROBABILITY_FEEDBACK);
else
probability_cutoff = PARAM_VALUE (TRACER_MIN_BRANCH_PROBABILITY);
@@ -232,7 +232,7 @@ tail_duplicate ()
weighted_insns += n * bb->frequency;
}
- if (profile_info.count_profiles_merged && flag_branch_probabilities)
+ if (profile_info && flag_branch_probabilities)
cover_insns = PARAM_VALUE (TRACER_DYNAMIC_COVERAGE_FEEDBACK);
else
cover_insns = PARAM_VALUE (TRACER_DYNAMIC_COVERAGE);