Commit cdb23767 by Nathan Sidwell Committed by Nathan Sidwell

Makefile.in (LIBGCC_DEPS): Add gcov headers.

	* 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.

From-SVN: r65990
parent 2be3b5ce
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> 2003-04-23 Roger Sayle <roger@eyesopen.com>
PR optimization/10339 PR optimization/10339
......
...@@ -1112,9 +1112,9 @@ LIBGCC_DEPS = $(GCC_PASSES) $(LANGUAGES) stmp-int-hdrs $(STMP_FIXPROTO) \ ...@@ -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 \ $(MACHMODE_H) longlong.h gbl-ctors.h config.status stmp-int-hdrs \
tsystem.h $(FPBIT) $(DPBIT) $(TPBIT) $(LIB2ADD) \ tsystem.h $(FPBIT) $(DPBIT) $(TPBIT) $(LIB2ADD) \
$(LIB2ADD_ST) $(LIB2ADDEH) $(LIB2ADDEHDEP) $(EXTRA_PARTS) \ $(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) libgcc.a: $(LIBGCC_DEPS)
$(MAKE) GCC_FOR_TARGET="$(GCC_FOR_TARGET)" \ $(MAKE) GCC_FOR_TARGET="$(GCC_FOR_TARGET)" \
......
...@@ -155,6 +155,10 @@ typedef struct edge_def { ...@@ -155,6 +155,10 @@ typedef struct edge_def {
#define EDGE_COMPLEX (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL | EDGE_EH) #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. */ /* Declared in cfgloop.h. */
struct loop; struct loop;
struct loops; struct loops;
......
...@@ -51,10 +51,8 @@ struct function_list ...@@ -51,10 +51,8 @@ struct function_list
{ {
struct function_list *next; /* next function */ struct function_list *next; /* next function */
const char *name; /* function name */ const char *name; /* function name */
unsigned cfg_checksum; /* function checksum */ unsigned checksum; /* function checksum */
unsigned n_counter_sections; /* number of counter sections */ unsigned n_ctrs[GCOV_COUNTERS];/* number of counters. */
struct gcov_counter_section counter_sections[MAX_COUNTER_SECTIONS];
/* the sections */
}; };
/* Counts information for a function. */ /* Counts information for a function. */
...@@ -62,15 +60,12 @@ typedef struct counts_entry ...@@ -62,15 +60,12 @@ typedef struct counts_entry
{ {
/* We hash by */ /* We hash by */
char *function_name; char *function_name;
unsigned section; unsigned ctr;
/* Store */ /* Store */
unsigned checksum; unsigned checksum;
unsigned n_counts;
gcov_type *counts; gcov_type *counts;
unsigned merged; struct gcov_ctr_summary summary;
gcov_type max_counter;
gcov_type max_counter_sum;
/* Workspace */ /* Workspace */
struct counts_entry *chain; struct counts_entry *chain;
...@@ -80,9 +75,13 @@ typedef struct counts_entry ...@@ -80,9 +75,13 @@ typedef struct counts_entry
static struct function_list *functions_head = 0; static struct function_list *functions_head = 0;
static struct function_list **functions_tail = &functions_head; 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. */ /* Name of the output file for coverage output file. */
static char *bbg_file_name; static char *bbg_file_name;
...@@ -95,8 +94,8 @@ static char *da_file_name; ...@@ -95,8 +94,8 @@ static char *da_file_name;
/* Hash table of count data. */ /* Hash table of count data. */
static htab_t counts_hash = NULL; static htab_t counts_hash = NULL;
/* The name of the count table. Used by the edge profiling code. */ /* The names of the counter tables. */
static GTY(()) rtx profiler_label; static GTY(()) rtx ctr_labels[GCOV_COUNTERS];
/* Forward declarations. */ /* Forward declarations. */
static hashval_t htab_counts_entry_hash PARAMS ((const void *)); static hashval_t htab_counts_entry_hash PARAMS ((const void *));
...@@ -105,16 +104,11 @@ static void htab_counts_entry_del PARAMS ((void *)); ...@@ -105,16 +104,11 @@ static void htab_counts_entry_del PARAMS ((void *));
static void read_counts_file PARAMS ((void)); static void read_counts_file PARAMS ((void));
static unsigned compute_checksum PARAMS ((void)); static unsigned compute_checksum PARAMS ((void));
static unsigned checksum_string PARAMS ((unsigned, const char *)); static unsigned checksum_string PARAMS ((unsigned, const char *));
static void set_purpose PARAMS ((tree, tree)); static tree build_fn_info_type PARAMS ((unsigned));
static rtx label_for_tag PARAMS ((unsigned)); static tree build_fn_info_value PARAMS ((const struct function_list *, tree));
static tree build_counter_section_fields PARAMS ((void)); static tree build_ctr_info_type PARAMS ((void));
static tree build_counter_section_value PARAMS ((unsigned, unsigned)); static tree build_ctr_info_value PARAMS ((unsigned, tree));
static tree build_counter_section_data_fields PARAMS ((void)); static tree build_gcov_info 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 void create_coverage PARAMS ((void)); static void create_coverage PARAMS ((void));
...@@ -124,7 +118,7 @@ htab_counts_entry_hash (of) ...@@ -124,7 +118,7 @@ htab_counts_entry_hash (of)
{ {
const counts_entry_t *entry = 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 static int
...@@ -136,7 +130,7 @@ htab_counts_entry_eq (of1, of2) ...@@ -136,7 +130,7 @@ htab_counts_entry_eq (of1, of2)
const counts_entry_t *entry2 = of2; const counts_entry_t *entry2 = of2;
return !strcmp (entry1->function_name, entry2->function_name) return !strcmp (entry1->function_name, entry2->function_name)
&& entry1->section == entry2->section; && entry1->ctr == entry2->ctr;
} }
static void static void
...@@ -213,8 +207,6 @@ read_counts_file () ...@@ -213,8 +207,6 @@ read_counts_file ()
for (entry = summaried; entry; entry = chain) for (entry = summaried; entry; entry = chain)
{ {
chain = entry->chain; chain = entry->chain;
entry->max_counter_sum += entry->max_counter;
entry->chain = NULL; entry->chain = NULL;
} }
summaried = NULL; summaried = NULL;
...@@ -230,34 +222,38 @@ read_counts_file () ...@@ -230,34 +222,38 @@ read_counts_file ()
seen_summary = 1; seen_summary = 1;
for (entry = summaried; entry; entry = entry->chain) for (entry = summaried; entry; entry = entry->chain)
{ {
entry->merged += summary.runs; struct gcov_ctr_summary *csum = &summary.ctrs[entry->ctr];
if (entry->max_counter < summary.arc_sum_max)
entry->max_counter = summary.arc_sum_max; 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) else if (GCOV_TAG_IS_COUNTER (tag) && function_name_buffer)
&& function_name_buffer)
{ {
counts_entry_t **slot, *entry, elt; counts_entry_t **slot, *entry, elt;
unsigned n_counts = length / 8; unsigned n_counts = length / 8;
unsigned ix; unsigned ix;
elt.function_name = function_name_buffer; elt.function_name = function_name_buffer;
elt.section = tag; elt.ctr = GCOV_COUNTER_FOR_TAG (tag);
slot = (counts_entry_t **) htab_find_slot slot = (counts_entry_t **) htab_find_slot
(counts_hash, &elt, INSERT); (counts_hash, &elt, INSERT);
entry = *slot; entry = *slot;
if (!entry) if (!entry)
{ {
*slot = entry = xmalloc (sizeof (counts_entry_t)); *slot = entry = xcalloc (1, sizeof (counts_entry_t));
entry->function_name = xstrdup (function_name_buffer); entry->function_name = xstrdup (elt.function_name);
entry->section = tag; entry->ctr = elt.ctr;
entry->checksum = checksum; entry->checksum = checksum;
entry->n_counts = n_counts; entry->summary.num = n_counts;
entry->counts = xcalloc (n_counts, sizeof (gcov_type)); 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); warning ("profile mismatch for `%s'", function_name_buffer);
htab_delete (counts_hash); htab_delete (counts_hash);
...@@ -292,13 +288,11 @@ read_counts_file () ...@@ -292,13 +288,11 @@ read_counts_file ()
/* Returns the counters for a particular tag. */ /* Returns the counters for a particular tag. */
gcov_type * 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; counts_entry_t *entry, elt;
profile_info.max_counter_in_program = 0;
profile_info.count_profiles_merged = 0;
/* No hash table, no counts. */ /* No hash table, no counts. */
if (!counts_hash) if (!counts_hash)
{ {
...@@ -313,7 +307,7 @@ get_coverage_counts (unsigned tag, unsigned expected) ...@@ -313,7 +307,7 @@ get_coverage_counts (unsigned tag, unsigned expected)
elt.function_name elt.function_name
= (char *) IDENTIFIER_POINTER = (char *) IDENTIFIER_POINTER
(DECL_ASSEMBLER_NAME (current_function_decl)); (DECL_ASSEMBLER_NAME (current_function_decl));
elt.section = tag; elt.ctr = counter;
entry = htab_find (counts_hash, &elt); entry = htab_find (counts_hash, &elt);
if (!entry) if (!entry)
{ {
...@@ -321,19 +315,50 @@ get_coverage_counts (unsigned tag, unsigned expected) ...@@ -321,19 +315,50 @@ get_coverage_counts (unsigned tag, unsigned expected)
return 0; return 0;
} }
if (expected != entry->n_counts if (expected != entry->summary.num
|| compute_checksum () != entry->checksum) || compute_checksum () != entry->checksum)
{ {
warning ("profile mismatch for `%s'", elt.function_name); warning ("profile mismatch for `%s'", elt.function_name);
return NULL; return NULL;
} }
profile_info.count_profiles_merged = entry->merged; if (summary)
profile_info.max_counter_in_program = entry->max_counter_sum; *summary = &entry->summary;
return entry->counts; 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 /* Generate a checksum for a string. CHKSUM is the current
checksum. */ checksum. */
...@@ -427,8 +452,7 @@ coverage_end_function () ...@@ -427,8 +452,7 @@ coverage_end_function ()
bbg_file_opened = -1; bbg_file_opened = -1;
} }
for (i = 0; i != profile_info.n_sections; i++) if (fn_ctr_mask)
if (profile_info.section_info[i].n_counters_now)
{ {
struct function_list *item; struct function_list *item;
...@@ -441,176 +465,32 @@ coverage_end_function () ...@@ -441,176 +465,32 @@ coverage_end_function ()
item->next = 0; item->next = 0;
item->name = xstrdup (IDENTIFIER_POINTER item->name = xstrdup (IDENTIFIER_POINTER
(DECL_ASSEMBLER_NAME (current_function_decl))); (DECL_ASSEMBLER_NAME (current_function_decl)));
item->cfg_checksum = compute_checksum (); item->checksum = compute_checksum ();
item->n_counter_sections = 0; for (i = 0; i != GCOV_COUNTERS; i++)
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 = item->n_ctrs[i] = fn_n_ctrs[i];
profile_info.section_info[i].tag; prg_n_ctrs[i] += fn_n_ctrs[i];
item->counter_sections[item->n_counter_sections].n_counters = fn_n_ctrs[i] = 0;
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; prg_ctr_mask |= fn_ctr_mask;
fn_ctr_mask = 0;
} }
bbg_function_announced = 0; bbg_function_announced = 0;
} }
/* Set FIELDS as purpose to VALUE. */ /* Creates the gcov_fn_info RECORD_TYPE. */
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;
}
/* 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 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; 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,
TYPE_QUAL_CONST));
/* 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;
/* counters */
field = build_decl (FIELD_DECL, NULL_TREE, gcov_ptr_type);
TREE_CHAIN (field) = fields;
fields = field;
return fields;
}
/* Creates value of struct counter_section_data (in gcov-io.h). */
static tree
build_counter_section_data_value (tag, n_counters)
unsigned tag;
unsigned n_counters;
{
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)),
value);
/* n_counters */
value = tree_cons (NULL_TREE,
convert (unsigned_type_node,
build_int_2 (n_counters, 0)),
value);
/* 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);
return value;
}
/* Creates fields for struct function_info type (in gcov-io.h). */
static tree
build_function_info_fields ()
{
tree field, fields, counter_section_fields, counter_section_type;
tree counter_sections_ptr_type;
tree string_type = tree string_type =
build_pointer_type (build_qualified_type (char_type_node, build_pointer_type (build_qualified_type (char_type_node,
TYPE_QUAL_CONST)); TYPE_QUAL_CONST));
tree array_type;
/* name */ /* name */
fields = build_decl (FIELD_DECL, NULL_TREE, string_type); fields = build_decl (FIELD_DECL, NULL_TREE, string_type);
...@@ -619,222 +499,188 @@ build_function_info_fields () ...@@ -619,222 +499,188 @@ build_function_info_fields ()
TREE_CHAIN (field) = fields; TREE_CHAIN (field) = fields;
fields = field; fields = field;
/* n_counter_sections */ array_type = build_index_type (build_int_2 (counters - 1, 0));
field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node); array_type = build_array_type (unsigned_type_node, array_type);
TREE_CHAIN (field) = fields;
fields = field;
/* counter_sections */ /* counters */
counter_section_fields = build_counter_section_fields (); field = build_decl (FIELD_DECL, NULL_TREE, array_type);
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; TREE_CHAIN (field) = fields;
fields = field; fields = field;
return fields; finish_builtin_struct (type, "__gcov_fn_info", fields, NULL_TREE);
return type;
} }
/* Creates value for struct function_info (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 static tree
build_function_info_value (function) build_fn_info_value (function, type)
struct function_list *function; const struct function_list *function;
tree type;
{ {
tree value = NULL_TREE; tree value = NULL_TREE;
tree fields = TYPE_FIELDS (type);
size_t name_len = strlen (function->name); size_t name_len = strlen (function->name);
tree fname = build_string (name_len + 1, function->name); tree fname = build_string (name_len + 1, function->name);
tree string_type = tree string_type =
build_pointer_type (build_qualified_type (char_type_node, build_pointer_type (build_qualified_type (char_type_node,
TYPE_QUAL_CONST)); TYPE_QUAL_CONST));
tree counter_section_fields, counter_section_type, counter_sections_value; unsigned ix;
tree counter_sections_ptr_type, counter_sections_array_type; tree array_value = NULL_TREE;
unsigned i;
/* name */ /* name */
TREE_TYPE (fname) = TREE_TYPE (fname) =
build_array_type (char_type_node, build_array_type (char_type_node,
build_index_type (build_int_2 (name_len, 0))); build_index_type (build_int_2 (name_len, 0)));
value = tree_cons (NULL_TREE, value = tree_cons (fields,
build1 (ADDR_EXPR, build1 (ADDR_EXPR, string_type, fname),
string_type,
fname),
value); value);
fields = TREE_CHAIN (fields);
/* checksum */ /* checksum */
value = tree_cons (NULL_TREE, value = tree_cons (fields,
convert (unsigned_type_node, convert (unsigned_type_node,
build_int_2 (function->cfg_checksum, 0)), build_int_2 (function->checksum, 0)),
value); value);
fields = TREE_CHAIN (fields);
/* n_counter_sections */ /* counters */
for (ix = 0; ix != GCOV_COUNTERS; ix++)
value = tree_cons (NULL_TREE, if (prg_ctr_mask & (1 << ix))
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 tree counters = convert (unsigned_type_node,
= build_counter_section_value (function->counter_sections[i].tag, build_int_2 (function->n_ctrs[ix], 0));
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) array_value = tree_cons (NULL_TREE, counters, array_value);
{
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);
} }
else
counter_sections_value = null_pointer_node;
value = tree_cons (NULL_TREE, counter_sections_value, 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; return value;
} }
/* Creates fields of struct gcov_info type (in gcov-io.h). */ /* Creates the gcov_ctr_info RECORD_TYPE. */
static tree static tree
build_gcov_info_fields (gcov_info_type) build_ctr_info_type ()
tree gcov_info_type;
{ {
tree field, fields; tree type = (*lang_hooks.types.make_type) (RECORD_TYPE);
char *filename; tree field, fields = NULL_TREE;
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 */ /* counters */
fields = build_decl (FIELD_DECL, NULL_TREE, long_unsigned_type_node); field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
TREE_CHAIN (field) = fields;
fields = field;
/* next -- NULL */ /* values */
field = build_decl (FIELD_DECL, NULL_TREE, field = build_decl (FIELD_DECL, NULL_TREE,
build_pointer_type build_pointer_type (make_signed_type (GCOV_TYPE_SIZE)));
(build_qualified_type
(gcov_info_type, TYPE_QUAL_CONST)));
TREE_CHAIN (field) = fields; TREE_CHAIN (field) = fields;
fields = field; fields = field;
/* Filename */ finish_builtin_struct (type, "__gcov_ctr_info", fields, NULL_TREE);
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); return type;
TREE_CHAIN (field) = fields; }
fields = field;
/* Workspace */ /* Creates a CONSTRUCTOR for a gcov_ctr_info. COUNTER is
field = build_decl (FIELD_DECL, NULL_TREE, long_integer_type_node); the counter being processed and TYPE is the gcov_ctr_info
TREE_CHAIN (field) = fields; RECORD_TYPE. */
fields = field;
/* number of functions */ static tree
field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node); build_ctr_info_value (counter, type)
TREE_CHAIN (field) = fields; unsigned counter;
fields = field; tree type;
{
tree value = NULL_TREE;
tree fields = TYPE_FIELDS (type);
/* function_info table */ /* counters */
function_info_fields = build_function_info_fields (); value = tree_cons (fields,
function_info_type = (*lang_hooks.types.make_type) (RECORD_TYPE); convert (unsigned_type_node,
finish_builtin_struct (function_info_type, "__function_info", build_int_2 (prg_n_ctrs[counter], 0)),
function_info_fields, NULL_TREE); value);
function_info_ptr_type = fields = TREE_CHAIN (fields);
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 */ if (prg_n_ctrs[counter])
field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node); {
TREE_CHAIN (field) = fields; tree array_type, array;
fields = field;
/* counter sections */ array_type = build_index_type (build_int_2 (prg_n_ctrs[counter] - 1, 0));
counter_section_data_fields = build_counter_section_data_fields (); array_type = build_array_type (TREE_TYPE (TREE_TYPE (fields)),
counter_section_data_type = (*lang_hooks.types.make_type) (RECORD_TYPE); array_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);
TREE_CHAIN (field) = fields;
fields = field;
return fields; 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
value = tree_cons (fields, null_pointer_node, value);
value = build_constructor (type, nreverse (value));
return value;
} }
/* Creates struct gcov_info value (in gcov-io.h). */ /* Creates the gcov_info RECORD_TYPE and initializer for it. Returns a
CONSTRUCTOR. */
static tree static tree
build_gcov_info_value () build_gcov_info ()
{ {
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 value = NULL_TREE;
tree filename_string; tree filename_string;
char *filename; char *filename;
int filename_len; int filename_len;
unsigned n_functions, i; unsigned n_fns;
struct function_list *item; const struct function_list *fn;
tree string_type = tree string_type;
build_pointer_type (build_qualified_type (char_type_node,
TYPE_QUAL_CONST)); /* Count the number of active counters. */
tree function_info_fields, function_info_type, function_info_ptr_type; for (n_ctr_types = 0, ix = 0; ix != GCOV_COUNTERS; ix++)
tree functions; if (prg_ctr_mask & (1 << ix))
tree counter_section_data_fields, counter_section_data_type; n_ctr_types++;
tree counter_section_data_ptr_type, counter_sections;
type = (*lang_hooks.types.make_type) (RECORD_TYPE);
const_type = build_qualified_type (type, TYPE_QUAL_CONST);
/* Version ident */ /* Version ident */
value = tree_cons (NULL_TREE, field = build_decl (FIELD_DECL, NULL_TREE, long_unsigned_type_node);
convert (long_unsigned_type_node, TREE_CHAIN (field) = fields;
fields = field;
value = tree_cons (field, convert (long_unsigned_type_node,
build_int_2 (GCOV_VERSION, 0)), build_int_2 (GCOV_VERSION, 0)),
value); value);
/* next -- NULL */ /* 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 */ /* 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 = getpwd ();
filename = (filename && da_file_name[0] != '/' filename = (filename && da_file_name[0] != '/'
? concat (filename, "/", da_file_name, NULL) ? concat (filename, "/", da_file_name, NULL)
...@@ -846,144 +692,99 @@ build_gcov_info_value () ...@@ -846,144 +692,99 @@ build_gcov_info_value ()
TREE_TYPE (filename_string) = TREE_TYPE (filename_string) =
build_array_type (char_type_node, build_array_type (char_type_node,
build_index_type (build_int_2 (filename_len, 0))); build_index_type (build_int_2 (filename_len, 0)));
value = tree_cons (NULL_TREE, value = tree_cons (field, build1 (ADDR_EXPR, string_type, filename_string),
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); value);
/* function_info table */ /* Build the fn_info type and initializer. */
function_info_fields = build_function_info_fields (); fn_info_type = build_fn_info_type (n_ctr_types);
function_info_type = (*lang_hooks.types.make_type) (RECORD_TYPE); fn_info_ptr_type = build_pointer_type (build_qualified_type
function_info_ptr_type = (fn_info_type, TYPE_QUAL_CONST));
build_pointer_type ( for (fn = functions_head, n_fns = 0; fn; fn = fn->next, n_fns++)
build_qualified_type (function_info_type, fn_info_value = tree_cons (NULL_TREE,
TYPE_QUAL_CONST)); build_fn_info_value (fn, fn_info_type),
functions = NULL_TREE; fn_info_value);
for (item = functions_head; item != 0; item = item->next) if (n_fns)
{
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)
{ {
tree array_type; tree array_type;
array_type = build_array_type ( array_type = build_index_type (build_int_2 (n_fns - 1, 0));
function_info_type, array_type = build_array_type (fn_info_type, array_type);
build_index_type (build_int_2 (n_functions - 1, 0)));
functions = build_constructor (array_type, nreverse (functions)); fn_info_value = build_constructor (array_type, nreverse (fn_info_value));
functions = build1 (ADDR_EXPR, fn_info_value = build1 (ADDR_EXPR, fn_info_ptr_type, fn_info_value);
function_info_ptr_type,
functions);
} }
else else
functions = null_pointer_node; fn_info_value = null_pointer_node;
value = tree_cons (NULL_TREE, functions, value); /* 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);
/* n_counter_sections */ /* fn_info table */
value = tree_cons (NULL_TREE, 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);
/* 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, convert (unsigned_type_node,
build_int_2 (profile_info.n_sections, 0)), build_int_2 (prg_ctr_mask, 0)),
value); value);
/* counter sections */ /* counters */
counter_section_data_fields = build_counter_section_data_fields (); ctr_info_type = build_ctr_info_type ();
counter_section_data_type = (*lang_hooks.types.make_type) (RECORD_TYPE); ctr_info_ary_type = build_index_type (build_int_2 (n_ctr_types, 0));
counter_sections = NULL_TREE; ctr_info_ary_type = build_array_type (ctr_info_type, ctr_info_ary_type);
for (i = 0; i < profile_info.n_sections; i++) for (ix = 0; ix != GCOV_COUNTERS; ix++)
{ if (prg_ctr_mask & (1 << ix))
tree counter_sections_value = ctr_info_value = tree_cons (NULL_TREE,
build_counter_section_data_value ( build_ctr_info_value (ix, ctr_info_type),
profile_info.section_info[i].tag, ctr_info_value);
profile_info.section_info[i].n_counters); ctr_info_value = build_constructor (ctr_info_ary_type,
set_purpose (counter_sections_value, counter_section_data_fields); nreverse (ctr_info_value));
counter_sections =
tree_cons (NULL_TREE, field = build_decl (FIELD_DECL, NULL_TREE, ctr_info_ary_type);
build_constructor (counter_section_data_type, TREE_CHAIN (field) = fields;
nreverse (counter_sections_value)), fields = field;
counter_sections); value = tree_cons (field, ctr_info_value, value);
}
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) finish_builtin_struct (type, "__gcov_info", fields, NULL_TREE);
{
tree cst_type = build_index_type (build_int_2 (profile_info.n_sections-1, value = build_constructor (type, nreverse (value));
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);
return 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 counters. The structures used here must match those defined in
gcov-io.h. Write out the constructor to call __gcov_init. */ gcov-io.h. Write out the constructor to call __gcov_init. */
static void static void
create_coverage () create_coverage ()
{ {
tree gcov_info_fields, gcov_info_type, gcov_info_value, gcov_info; tree gcov_info, gcov_info_value;
char name[20]; char name[20];
char *ctor_name; char *ctor_name;
tree ctor; tree ctor;
rtx gcov_info_address; rtx gcov_info_address;
int save_flag_inline_functions = flag_inline_functions; int save_flag_inline_functions = flag_inline_functions;
unsigned i;
for (i = 0; i < profile_info.n_sections; i++) if (!prg_ctr_mask)
if (profile_info.section_info[i].n_counters)
break;
if (i == profile_info.n_sections)
return; return;
gcov_info_type = (*lang_hooks.types.make_type) (RECORD_TYPE); gcov_info_value = build_gcov_info ();
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 = build (VAR_DECL, gcov_info_type, NULL_TREE, NULL_TREE); gcov_info = build (VAR_DECL, TREE_TYPE (gcov_info_value),
DECL_INITIAL (gcov_info) = NULL_TREE, NULL_TREE);
build_constructor (gcov_info_type, nreverse (gcov_info_value)); DECL_INITIAL (gcov_info) = gcov_info_value;
TREE_STATIC (gcov_info) = 1; TREE_STATIC (gcov_info) = 1;
ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 0); ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 0);
...@@ -1044,59 +845,6 @@ create_coverage () ...@@ -1044,59 +845,6 @@ create_coverage ()
DEFAULT_INIT_PRIORITY); 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 /* Perform file-level initialization. Read in data file, generate name
of graph file. */ of graph file. */
...@@ -1142,5 +890,4 @@ coverage_finish () ...@@ -1142,5 +890,4 @@ coverage_finish ()
} }
} }
#include "gt-coverage.h" #include "gt-coverage.h"
...@@ -23,50 +23,14 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA ...@@ -23,50 +23,14 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "gcov-io.h" #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_init (const char *);
extern void coverage_finish (void); extern void coverage_finish (void);
extern void coverage_end_function (void); extern void coverage_end_function (void);
extern int coverage_begin_output (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 #endif
...@@ -35,7 +35,7 @@ static void tag_function PARAMS ((const char *, unsigned, unsigned)); ...@@ -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_blocks PARAMS ((const char *, unsigned, unsigned));
static void tag_arcs 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_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)); static void tag_summary PARAMS ((const char *, unsigned, unsigned));
extern int main PARAMS ((int, char **)); extern int main PARAMS ((int, char **));
...@@ -59,15 +59,13 @@ static const tag_format_t tag_table[] = ...@@ -59,15 +59,13 @@ static const tag_format_t tag_table[] =
{ {
{0, "NOP", NULL}, {0, "NOP", NULL},
{0, "UNKNOWN", NULL}, {0, "UNKNOWN", NULL},
{0, "COUNTERS", tag_counters},
{GCOV_TAG_FUNCTION, "FUNCTION", tag_function}, {GCOV_TAG_FUNCTION, "FUNCTION", tag_function},
{GCOV_TAG_BLOCKS, "BLOCKS", tag_blocks}, {GCOV_TAG_BLOCKS, "BLOCKS", tag_blocks},
{GCOV_TAG_ARCS, "ARCS", tag_arcs}, {GCOV_TAG_ARCS, "ARCS", tag_arcs},
{GCOV_TAG_LINES, "LINES", tag_lines}, {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_OBJECT_SUMMARY, "OBJECT_SUMMARY", tag_summary},
{GCOV_TAG_PROGRAM_SUMMARY, "PROGRAM_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} {0, NULL, NULL}
}; };
...@@ -208,7 +206,7 @@ dump_file (filename) ...@@ -208,7 +206,7 @@ dump_file (filename)
for (format = tag_table; format->name; format++) for (format = tag_table; format->name; format++)
if (format->tag == tag) if (format->tag == tag)
goto found; goto found;
format = &tag_table[1]; format = &tag_table[GCOV_TAG_IS_COUNTER (tag) ? 2 : 1];
found:; found:;
if (tag) if (tag)
{ {
...@@ -364,14 +362,16 @@ tag_lines (filename, tag, length) ...@@ -364,14 +362,16 @@ tag_lines (filename, tag, length)
} }
static void static void
tag_arc_counts (filename, tag, length) tag_counters (filename, tag, length)
const char *filename ATTRIBUTE_UNUSED; const char *filename ATTRIBUTE_UNUSED;
unsigned tag ATTRIBUTE_UNUSED; unsigned tag ATTRIBUTE_UNUSED;
unsigned length ATTRIBUTE_UNUSED; unsigned length ATTRIBUTE_UNUSED;
{ {
static const char *const counter_names[] = GCOV_COUNTER_NAMES;
unsigned n_counts = length / 8; 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) if (flag_dump_contents)
{ {
unsigned ix; unsigned ix;
...@@ -395,20 +395,21 @@ tag_summary (filename, tag, length) ...@@ -395,20 +395,21 @@ tag_summary (filename, tag, length)
unsigned length ATTRIBUTE_UNUSED; unsigned length ATTRIBUTE_UNUSED;
{ {
struct gcov_summary summary; struct gcov_summary summary;
unsigned ix;
gcov_read_summary (&summary); gcov_read_summary (&summary);
printf (" checksum=0x%08x", summary.checksum); printf (" checksum=0x%08x", summary.checksum);
printf ("\n%s:\t\truns=%u, arcs=%u", filename, for (ix = 0; ix != GCOV_COUNTERS; ix++)
summary.runs, summary.arcs); {
printf ("\n%s:\t\tarc_sum=", filename); printf ("\n%sL\t\tcounts=%u, runs=%u", filename,
printf (HOST_WIDEST_INT_PRINT_DEC, summary.ctrs[ix].num, summary.ctrs[ix].runs);
(HOST_WIDEST_INT)summary.arc_sum);
printf (", arc_max_one="); printf (", sum_all=" HOST_WIDEST_INT_PRINT_DEC,
printf (HOST_WIDEST_INT_PRINT_DEC, (HOST_WIDEST_INT)summary.ctrs[ix].sum_all);
(HOST_WIDEST_INT)summary.arc_max_one); printf (", run_max=" HOST_WIDEST_INT_PRINT_DEC,
printf (", sum_max="); (HOST_WIDEST_INT)summary.ctrs[ix].run_max);
printf (HOST_WIDEST_INT_PRINT_DEC, printf (", sum_max=" HOST_WIDEST_INT_PRINT_DEC,
(HOST_WIDEST_INT)summary.arc_sum_max); (HOST_WIDEST_INT)summary.ctrs[ix].sum_max);
}
} }
...@@ -305,15 +305,20 @@ gcov_write_length (unsigned long position) ...@@ -305,15 +305,20 @@ gcov_write_length (unsigned long position)
GCOV_LINKAGE void GCOV_LINKAGE void
gcov_write_summary (unsigned tag, const struct gcov_summary *summary) gcov_write_summary (unsigned tag, const struct gcov_summary *summary)
{ {
unsigned ix;
const struct gcov_ctr_summary *csum;
unsigned long base; unsigned long base;
base = gcov_write_tag (tag); base = gcov_write_tag (tag);
gcov_write_unsigned (summary->checksum); gcov_write_unsigned (summary->checksum);
gcov_write_unsigned (summary->runs); for (csum = summary->ctrs, ix = GCOV_COUNTERS; ix--; csum++)
gcov_write_unsigned (summary->arcs); {
gcov_write_counter (summary->arc_sum); gcov_write_unsigned (csum->num);
gcov_write_counter (summary->arc_max_one); gcov_write_unsigned (csum->runs);
gcov_write_counter (summary->arc_sum_max); gcov_write_counter (csum->sum_all);
gcov_write_counter (csum->run_max);
gcov_write_counter (csum->sum_max);
}
gcov_write_length (base); gcov_write_length (base);
} }
#endif /* IN_LIBGCOV */ #endif /* IN_LIBGCOV */
...@@ -406,15 +411,20 @@ gcov_read_string () ...@@ -406,15 +411,20 @@ gcov_read_string ()
GCOV_LINKAGE void GCOV_LINKAGE void
gcov_read_summary (struct gcov_summary *summary) gcov_read_summary (struct gcov_summary *summary)
{ {
unsigned ix;
struct gcov_ctr_summary *csum;
summary->checksum = gcov_read_unsigned (); summary->checksum = gcov_read_unsigned ();
summary->runs = gcov_read_unsigned (); for (csum = summary->ctrs, ix = GCOV_COUNTERS; ix--; csum++)
summary->arcs = gcov_read_unsigned (); {
summary->arc_sum = gcov_read_counter (); csum->num = gcov_read_unsigned ();
summary->arc_max_one = gcov_read_counter (); csum->runs = gcov_read_unsigned ();
summary->arc_sum_max = gcov_read_counter (); csum->sum_all = gcov_read_counter ();
csum->run_max = gcov_read_counter ();
csum->sum_max = gcov_read_counter ();
}
} }
#if IN_GCOV > 0 #if IN_GCOV > 0
/* Return the modification time of the current gcov file. */ /* Return the modification time of the current gcov file. */
......
...@@ -127,8 +127,9 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA ...@@ -127,8 +127,9 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
function-data: announce_function arc_counts function-data: announce_function arc_counts
announce_function: header string:name int32:checksum announce_function: header string:name int32:checksum
arc_counts: header int64:count* arc_counts: header int64:count*
summary: in32:checksum int32:runs int32:arcs int64:sum int64:max \ summary: int32:checksum {count-summary}GCOV_COUNTERS
int64:sum_max 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, The ANNOUNCE_FUNCTION record is the same as that in the BBG file,
but without the source location. but without the source location.
...@@ -160,6 +161,11 @@ typedef long gcov_type; ...@@ -160,6 +161,11 @@ typedef long gcov_type;
#else #else
typedef long long gcov_type; typedef long long gcov_type;
#endif #endif
#if defined (TARGET_HAS_F_SETLKW)
#define GCOV_LOCKED 1
#else
#define GCOV_LOCKED 0
#endif
#endif /* IN_LIBGCOV */ #endif /* IN_LIBGCOV */
#if IN_GCOV #if IN_GCOV
typedef HOST_WIDEST_INT gcov_type; typedef HOST_WIDEST_INT gcov_type;
...@@ -201,11 +207,26 @@ 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_BLOCKS ((unsigned)0x01410000)
#define GCOV_TAG_ARCS ((unsigned)0x01430000) #define GCOV_TAG_ARCS ((unsigned)0x01430000)
#define GCOV_TAG_LINES ((unsigned)0x01450000) #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_OBJECT_SUMMARY ((unsigned)0xa1000000)
#define GCOV_TAG_PROGRAM_SUMMARY ((unsigned)0xa3000000) #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 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 the lsb of the current level, and zero on the current and outer
...@@ -231,44 +252,43 @@ typedef HOST_WIDEST_INT gcov_type; ...@@ -231,44 +252,43 @@ typedef HOST_WIDEST_INT gcov_type;
/* Structured records. */ /* 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. */ /* Object & program summary record. */
struct gcov_summary struct gcov_summary
{ {
unsigned checksum; /* checksum of program */ unsigned checksum; /* checksum of program */
unsigned runs; /* number of program runs */ struct gcov_ctr_summary ctrs[GCOV_COUNTERS];
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 */
}; };
/* Structures embedded in coveraged program. The structures generated /* Structures embedded in coveraged program. The structures generated
by write_profile must match these. */ 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 #if IN_LIBGCOV
/* Information about section of counters for an object file. */ /* Information about a single function. This uses the trailing array
struct gcov_counter_section_data 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. */ const char *name; /* (mangled) name of function */
unsigned n_counters; /* Number of counters in the section. */ unsigned checksum; /* function checksum */
gcov_type *counters; /* The data. */ unsigned n_ctrs[0]; /* instrumented counters */
}; };
/* Information about a single function. */ /* Information about counters. */
struct gcov_function_info struct gcov_ctr_info
{ {
const char *name; /* (mangled) name of function */ unsigned num; /* number of counters. */
unsigned checksum; /* function checksum */ gcov_type *values; /* their values. */
unsigned n_counter_sections; /* Number of types of counters */
const struct gcov_counter_section *counter_sections;
/* The section descriptions */
}; };
/* Information about a single object file. */ /* Information about a single object file. */
...@@ -278,14 +298,15 @@ struct gcov_info ...@@ -278,14 +298,15 @@ struct gcov_info
struct gcov_info *next; /* link to next, used by libgcc */ struct gcov_info *next; /* link to next, used by libgcc */
const char *filename; /* output file name */ const char *filename; /* output file name */
long wkspc; /* libgcc workspace */
unsigned n_functions; /* number of functions */ 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 */ unsigned ctr_mask; /* mask of counters instrumented. */
const struct gcov_counter_section_data *counter_sections; struct gcov_ctr_info counts[0]; /* count data. The number of bits
/* The data to be put into the sections. */ set in the ctr_mask field
determines how big this array
is. */
}; };
/* Register a new object file module. */ /* Register a new object file module. */
......
...@@ -1011,8 +1011,7 @@ read_count_file () ...@@ -1011,8 +1011,7 @@ read_count_file ()
if (tag == GCOV_TAG_OBJECT_SUMMARY) if (tag == GCOV_TAG_OBJECT_SUMMARY)
gcov_read_summary (&object_summary); gcov_read_summary (&object_summary);
else if (tag == GCOV_TAG_PROGRAM_SUMMARY else if (tag == GCOV_TAG_PROGRAM_SUMMARY)
|| tag == GCOV_TAG_INCORRECT_SUMMARY)
program_count++; program_count++;
else if (tag == GCOV_TAG_FUNCTION) else if (tag == GCOV_TAG_FUNCTION)
{ {
...@@ -1045,7 +1044,7 @@ read_count_file () ...@@ -1045,7 +1044,7 @@ read_count_file ()
goto cleanup; 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) if (length != 8 * fn->num_counts)
goto mismatch; goto mismatch;
...@@ -1801,7 +1800,8 @@ output_lines (gcov_file, src) ...@@ -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:Source:%s\n", "-", 0, src->name);
fprintf (gcov_file, "%9s:%5d:Graph:%s\n", "-", 0, bbg_file_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: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); fprintf (gcov_file, "%9s:%5d:Programs:%u\n", "-", 0, program_count);
source_file = fopen (src->name, "r"); source_file = fopen (src->name, "r");
......
...@@ -96,93 +96,91 @@ gcov_version_mismatch (struct gcov_info *ptr, unsigned version) ...@@ -96,93 +96,91 @@ gcov_version_mismatch (struct gcov_info *ptr, unsigned version)
static void static void
gcov_exit (void) gcov_exit (void)
{ {
struct gcov_info *ptr; struct gcov_info *gi_ptr;
unsigned ix, jx; struct gcov_summary this_program;
gcov_type program_max_one = 0; struct gcov_summary all;
gcov_type program_sum = 0;
unsigned program_arcs = 0; memset (&all, 0, sizeof (all));
struct gcov_summary last_prg; /* Find the totals for this execution. */
memset (&this_program, 0, sizeof (this_program));
last_prg.runs = 0; for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
for (ptr = gcov_list; ptr; ptr = ptr->next)
{ {
unsigned arc_data_index; const struct gcov_ctr_info *ci_ptr;
gcov_type *count_ptr; struct gcov_ctr_summary *cs_ptr;
unsigned t_ix;
if (!ptr->filename) for (t_ix = 0, ci_ptr = gi_ptr->counts, cs_ptr = this_program.ctrs;
continue; t_ix != GCOV_COUNTERS; t_ix++, cs_ptr++)
if ((1 << t_ix) & gi_ptr->ctr_mask)
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++; const gcov_type *c_ptr;
unsigned c_num;
if (count > program_max_one) cs_ptr->num += ci_ptr->num;
program_max_one = count; for (c_num = ci_ptr->num, c_ptr = ci_ptr->values; c_num--; c_ptr++)
program_sum += count; {
cs_ptr->sum_all += *c_ptr;
if (cs_ptr->run_max < *c_ptr)
cs_ptr->run_max = *c_ptr;
} }
program_arcs += ptr->counter_sections[arc_data_index].n_counters; 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 this_object;
struct gcov_summary local_prg; 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 error;
int merging; int merging;
unsigned long base; 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 tag, length;
unsigned arc_data_index, f_sect_index, sect_index; unsigned long summary_pos = 0;
long summary_pos = 0;
/* Totals for this object file. */
if (!ptr->filename) memset (&this_object, 0, sizeof (this_object));
continue; for (t_ix = c_ix = 0,
ci_ptr = gi_ptr->counts, cs_ptr = this_object.ctrs;
counters = malloc (sizeof (gcov_type *) * ptr->n_counter_sections); t_ix != GCOV_COUNTERS; t_ix++, cs_ptr++)
for (ix = 0; ix < ptr->n_counter_sections; ix++) if ((1 << t_ix) & gi_ptr->ctr_mask)
counters[ix] = ptr->counter_sections[ix].counters; {
const gcov_type *c_ptr;
for (arc_data_index = 0; unsigned c_num;
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) 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++)
{ {
/* For now; later we may want to just measure other profiles, cs_ptr->sum_all += *c_ptr;
but now I am lazy to check for all consequences. */ if (cs_ptr->run_max < *c_ptr)
abort (); cs_ptr->run_max = *c_ptr;
} }
for (ix = ptr->counter_sections[arc_data_index].n_counters, c_ix++;
count_ptr = ptr->counter_sections[arc_data_index].counters; ix--;) ci_ptr++;
{
gcov_type count = *count_ptr++;
if (count > object_max_one)
object_max_one = count;
} }
memset (&local_prg, 0, sizeof (local_prg)); /* Calculate the function_info stride. This depends on the
memset (&object, 0, sizeof (object)); number of counter types being measured. */
fi_stride = sizeof (struct gcov_fn_info) + c_ix * sizeof (unsigned);
/* Open for modification */ if (__alignof__ (struct gcov_fn_info) > sizeof (unsigned))
merging = gcov_open (ptr->filename, 0); {
fi_stride += __alignof__ (struct gcov_fn_info) - 1;
fi_stride &= ~(__alignof__ (struct gcov_fn_info) - 1);
}
/* Open for modification, if possible */
merging = gcov_open (gi_ptr->filename, 0);
if (!merging) if (!merging)
{ {
fprintf (stderr, "profiling:%s:Cannot open\n", ptr->filename); fprintf (stderr, "profiling:%s:Cannot open\n", gi_ptr->filename);
ptr->filename = 0;
continue; continue;
} }
...@@ -192,22 +190,22 @@ gcov_exit (void) ...@@ -192,22 +190,22 @@ gcov_exit (void)
if (gcov_read_unsigned () != GCOV_DATA_MAGIC) if (gcov_read_unsigned () != GCOV_DATA_MAGIC)
{ {
fprintf (stderr, "profiling:%s:Not a gcov data file\n", fprintf (stderr, "profiling:%s:Not a gcov data file\n",
ptr->filename); gi_ptr->filename);
read_fatal:; read_fatal:;
gcov_close (); gcov_close ();
ptr->filename = 0;
continue; continue;
} }
length = gcov_read_unsigned (); length = gcov_read_unsigned ();
if (length != GCOV_VERSION) if (length != GCOV_VERSION)
{ {
gcov_version_mismatch (ptr, length); gcov_version_mismatch (gi_ptr, length);
goto read_fatal; goto read_fatal;
} }
/* Merge execution counts for each function. */ /* Merge execution counts for each function. */
for (ix = ptr->n_functions, fn_info = ptr->functions; for (f_ix = gi_ptr->n_functions, fi_ptr = gi_ptr->functions; f_ix--;
ix--; fn_info++) fi_ptr = (const struct gcov_fn_info *)
((const char *) fi_ptr + fi_stride))
{ {
tag = gcov_read_unsigned (); tag = gcov_read_unsigned ();
length = gcov_read_unsigned (); length = gcov_read_unsigned ();
...@@ -216,42 +214,34 @@ gcov_exit (void) ...@@ -216,42 +214,34 @@ gcov_exit (void)
if (tag != GCOV_TAG_FUNCTION) if (tag != GCOV_TAG_FUNCTION)
{ {
read_mismatch:; read_mismatch:;
fprintf (stderr, "profiling:%s:Merge mismatch at %s\n", fprintf (stderr, "profiling:%s:Merge mismatch for %s\n",
ptr->filename, fn_info->name); gi_ptr->filename,
fi_ptr ? fi_ptr->name : "summaries");
goto read_fatal; goto read_fatal;
} }
if (strcmp (gcov_read_string (), fn_info->name) if (strcmp (gcov_read_string (), fi_ptr->name)
|| gcov_read_unsigned () != fn_info->checksum) || gcov_read_unsigned () != fi_ptr->checksum)
goto read_mismatch; goto read_mismatch;
/* Counters. */ for (c_ix = t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
for (f_sect_index = 0; if ((1 << t_ix) & gi_ptr->ctr_mask)
f_sect_index < fn_info->n_counter_sections;
f_sect_index++)
{ {
unsigned n_counters; unsigned n_counts;
gcov_type *c_ptr;
tag = gcov_read_unsigned (); tag = gcov_read_unsigned ();
length = gcov_read_unsigned (); length = gcov_read_unsigned ();
for (sect_index = 0; if (tag != GCOV_TAG_FOR_COUNTER (t_ix)
sect_index < ptr->n_counter_sections; || fi_ptr->n_ctrs[c_ix] * 8 != length)
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; goto read_mismatch;
c_ptr = values[c_ix];
n_counters = fn_info->counter_sections[f_sect_index].n_counters; for (n_counts = fi_ptr->n_ctrs[c_ix];
if (n_counters != length / 8) n_counts--; c_ptr++)
goto read_mismatch; *c_ptr += gcov_read_counter ();
values[c_ix] = c_ptr;
for (jx = 0; jx < n_counters; jx++) c_ix++;
counters[sect_index][jx] += gcov_read_counter ();
counters[sect_index] += n_counters;
} }
if ((error = gcov_is_error ())) if ((error = gcov_is_error ()))
goto read_error; goto read_error;
...@@ -266,108 +256,113 @@ gcov_exit (void) ...@@ -266,108 +256,113 @@ gcov_exit (void)
/* Check program summary */ /* Check program summary */
while (!gcov_is_eof ()) while (!gcov_is_eof ())
{ {
unsigned long base = gcov_position (); base = gcov_position ();
tag = gcov_read_unsigned (); tag = gcov_read_unsigned ();
gcov_read_unsigned (); gcov_read_unsigned ();
if (tag != GCOV_TAG_PROGRAM_SUMMARY) if (tag != GCOV_TAG_PROGRAM_SUMMARY)
goto read_mismatch; goto read_mismatch;
gcov_read_summary (&local_prg); gcov_read_summary (&program);
if ((error = gcov_is_error ())) if ((error = gcov_is_error ()))
{ {
read_error:; read_error:;
fprintf (stderr, error < 0 ? fprintf (stderr, error < 0 ?
"profiling:%s:Overflow merging\n" : "profiling:%s:Overflow merging\n" :
"profiling:%s:Error merging\n", "profiling:%s:Error merging\n",
ptr->filename); gi_ptr->filename);
goto read_fatal; goto read_fatal;
} }
if (local_prg.checksum != gcov_crc32) if (program.checksum != gcov_crc32)
{
memset (&local_prg, 0, sizeof (local_prg));
continue; 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));
summary_pos = base; summary_pos = base;
break; break;
} }
gcov_seek (0, 0); gcov_seek (0, 0);
} }
else
memset (&object, 0, sizeof (object));
if (!summary_pos)
memset (&program, 0, sizeof (program));
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;
}
}
object.runs++; program.checksum = gcov_crc32;
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;
/* Write out the data. */ /* Write out the data. */
gcov_write_unsigned (GCOV_DATA_MAGIC); gcov_write_unsigned (GCOV_DATA_MAGIC);
gcov_write_unsigned (GCOV_VERSION); gcov_write_unsigned (GCOV_VERSION);
/* Write execution counts for each function. */ /* Write execution counts for each function. */
for (ix = 0; ix < ptr->n_counter_sections; ix++) for (f_ix = gi_ptr->n_functions, fi_ptr = gi_ptr->functions; f_ix--;
counters[ix] = ptr->counter_sections[ix].counters; fi_ptr = (const struct gcov_fn_info *)
for (ix = ptr->n_functions, fn_info = ptr->functions; ix--; fn_info++) ((const char *) fi_ptr + fi_stride))
{ {
/* Announce function. */ /* Announce function. */
base = gcov_write_tag (GCOV_TAG_FUNCTION); base = gcov_write_tag (GCOV_TAG_FUNCTION);
gcov_write_string (fn_info->name); gcov_write_string (fi_ptr->name);
gcov_write_unsigned (fn_info->checksum); gcov_write_unsigned (fi_ptr->checksum);
gcov_write_length (base); gcov_write_length (base);
/* counters. */ for (c_ix = t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
for (f_sect_index = 0; if ((1 << t_ix) & gi_ptr->ctr_mask)
f_sect_index < fn_info->n_counter_sections;
f_sect_index++)
{ {
tag = fn_info->counter_sections[f_sect_index].tag; unsigned n_counts;
for (sect_index = 0; gcov_type *c_ptr;
sect_index < ptr->n_counter_sections;
sect_index++) base = gcov_write_tag (GCOV_TAG_FOR_COUNTER (t_ix));
if (ptr->counter_sections[sect_index].tag == tag) c_ptr = values[c_ix];
break; for (n_counts = fi_ptr->n_ctrs[c_ix]; n_counts--; c_ptr++)
if (sect_index == ptr->n_counter_sections) gcov_write_counter (*c_ptr);
abort (); values[c_ix] = c_ptr;
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); gcov_write_length (base);
c_ix++;
} }
} }
...@@ -375,39 +370,20 @@ is compiled without file locking support.\n", ...@@ -375,39 +370,20 @@ is compiled without file locking support.\n",
gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, &object); gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, &object);
/* Generate whole program statistics. */ /* Generate whole program statistics. */
local_prg.runs++; if (summary_pos)
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); gcov_seek (summary_pos, 0);
if (!local_prg.runs) else
ptr->wkspc = 0; gcov_seek_end ();
gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &local_prg); gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &program);
} if ((error = gcov_close ()))
if (gcov_close ())
{ {
fprintf (stderr, "profiling:%s:Error writing\n", ptr->filename); fprintf (stderr, error < 0 ?
ptr->filename = 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 /* Add a new object file onto the bb chain. Invoked automatically
...@@ -459,16 +435,20 @@ __gcov_init (struct gcov_info *info) ...@@ -459,16 +435,20 @@ __gcov_init (struct gcov_info *info)
void void
__gcov_flush (void) __gcov_flush (void)
{ {
struct gcov_info *ptr; const struct gcov_info *gi_ptr;
gcov_exit (); 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 (t_ix = 0, ci_ptr = gi_ptr->counts; t_ix != GCOV_COUNTERS; t_ix++)
for (i = ptr->counter_sections[j].n_counters; i--;) if ((1 << t_ix) & gi_ptr->ctr_mask)
ptr->counter_sections[j].counters[i] = 0; {
memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
ci_ptr++;
}
} }
} }
......
...@@ -75,7 +75,7 @@ make_compile='$(MAKE) GCC_FOR_TARGET="$(GCC_FOR_TARGET)" \ ...@@ -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" 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 # 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 # Dependencies for fp-bit.c
fpbit_c_dep='stmp-dirs config.status tsystem.h' fpbit_c_dep='stmp-dirs config.status tsystem.h'
......
...@@ -120,11 +120,9 @@ bool ...@@ -120,11 +120,9 @@ bool
maybe_hot_bb_p (bb) maybe_hot_bb_p (bb)
basic_block bb; basic_block bb;
{ {
if (profile_info.count_profiles_merged if (profile_info && flag_branch_probabilities
&& flag_branch_probabilities
&& (bb->count && (bb->count
< profile_info.max_counter_in_program < profile_info->sum_max / PARAM_VALUE (HOT_BB_COUNT_FRACTION)))
/ PARAM_VALUE (HOT_BB_COUNT_FRACTION)))
return false; return false;
if (bb->frequency < BB_FREQ_MAX / PARAM_VALUE (HOT_BB_FREQUENCY_FRACTION)) if (bb->frequency < BB_FREQ_MAX / PARAM_VALUE (HOT_BB_FREQUENCY_FRACTION))
return false; return false;
...@@ -137,11 +135,9 @@ bool ...@@ -137,11 +135,9 @@ bool
probably_cold_bb_p (bb) probably_cold_bb_p (bb)
basic_block bb; basic_block bb;
{ {
if (profile_info.count_profiles_merged if (profile_info && flag_branch_probabilities
&& flag_branch_probabilities
&& (bb->count && (bb->count
< profile_info.max_counter_in_program < profile_info->sum_max / PARAM_VALUE (HOT_BB_COUNT_FRACTION)))
/ PARAM_VALUE (HOT_BB_COUNT_FRACTION)))
return true; return true;
if (bb->frequency < BB_FREQ_MAX / PARAM_VALUE (HOT_BB_FREQUENCY_FRACTION)) if (bb->frequency < BB_FREQ_MAX / PARAM_VALUE (HOT_BB_FREQUENCY_FRACTION))
return true; return true;
...@@ -153,10 +149,8 @@ bool ...@@ -153,10 +149,8 @@ bool
probably_never_executed_bb_p (bb) probably_never_executed_bb_p (bb)
basic_block bb; basic_block bb;
{ {
if (profile_info.count_profiles_merged if (profile_info && flag_branch_probabilities)
&& flag_branch_probabilities) return ((bb->count + profile_info->runs / 2) / profile_info->runs) == 0;
return ((bb->count + profile_info.count_profiles_merged / 2)
/ profile_info.count_profiles_merged) == 0;
return false; return false;
} }
...@@ -1266,8 +1260,7 @@ compute_function_frequency () ...@@ -1266,8 +1260,7 @@ compute_function_frequency ()
{ {
basic_block bb; basic_block bb;
if (!profile_info.count_profiles_merged if (!profile_info || !flag_branch_probabilities)
|| !flag_branch_probabilities)
return; return;
cfun->function_frequency = FUNCTION_FREQUENCY_UNLIKELY_EXECUTED; cfun->function_frequency = FUNCTION_FREQUENCY_UNLIKELY_EXECUTED;
FOR_EACH_BB (bb) FOR_EACH_BB (bb)
......
...@@ -81,26 +81,6 @@ struct bb_info { ...@@ -81,26 +81,6 @@ struct bb_info {
gcov_type pred_count; 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 EDGE_INFO(e) ((struct edge_info *) (e)->aux)
#define BB_INFO(b) ((struct bb_info *) (b)->aux) #define BB_INFO(b) ((struct bb_info *) (b)->aux)
...@@ -110,6 +90,10 @@ typedef struct counts_entry ...@@ -110,6 +90,10 @@ typedef struct counts_entry
: ((bb) == EXIT_BLOCK_PTR \ : ((bb) == EXIT_BLOCK_PTR \
? last_basic_block + 1 : (bb)->index + 1)) ? 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 /* Collect statistics on the performance of this pass for the entire source
file. */ file. */
...@@ -195,16 +179,13 @@ get_exec_counts () ...@@ -195,16 +179,13 @@ get_exec_counts ()
num_edges++; 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) if (!counts)
return NULL; return NULL;
if (rtl_dump_file) if (rtl_dump_file && profile_info)
{ fprintf(rtl_dump_file, "Merged %u profiles with maximal count %u.\n",
fprintf(rtl_dump_file, "Merged %i profiles with maximal count %i.\n", profile_info->runs, (unsigned) profile_info->sum_max);
profile_info.count_profiles_merged,
(int)profile_info.max_counter_in_program);
}
return counts; return counts;
} }
...@@ -547,7 +528,6 @@ compute_branch_probabilities () ...@@ -547,7 +528,6 @@ compute_branch_probabilities ()
} }
free_aux_for_blocks (); free_aux_for_blocks ();
find_counters_section (GCOV_TAG_ARC_COUNTS)->present = 1;
} }
/* Instrument and/or analyze program behavior based on program flow graph. /* Instrument and/or analyze program behavior based on program flow graph.
...@@ -1013,7 +993,7 @@ static rtx ...@@ -1013,7 +993,7 @@ static rtx
gen_edge_profiler (edgeno) gen_edge_profiler (edgeno)
int edgeno; int edgeno;
{ {
rtx ref = coverage_counter_ref (GCOV_TAG_ARC_COUNTS, edgeno); rtx ref = coverage_counter_ref (GCOV_COUNTER_ARCS, edgeno);
rtx tmp; rtx tmp;
enum machine_mode mode = GET_MODE (ref); enum machine_mode mode = GET_MODE (ref);
rtx sequence; rtx sequence;
......
...@@ -211,7 +211,7 @@ tail_duplicate () ...@@ -211,7 +211,7 @@ tail_duplicate ()
int max_dup_insns; int max_dup_insns;
basic_block bb; 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); probability_cutoff = PARAM_VALUE (TRACER_MIN_BRANCH_PROBABILITY_FEEDBACK);
else else
probability_cutoff = PARAM_VALUE (TRACER_MIN_BRANCH_PROBABILITY); probability_cutoff = PARAM_VALUE (TRACER_MIN_BRANCH_PROBABILITY);
...@@ -232,7 +232,7 @@ tail_duplicate () ...@@ -232,7 +232,7 @@ tail_duplicate ()
weighted_insns += n * bb->frequency; 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); cover_insns = PARAM_VALUE (TRACER_DYNAMIC_COVERAGE_FEEDBACK);
else else
cover_insns = PARAM_VALUE (TRACER_DYNAMIC_COVERAGE); cover_insns = PARAM_VALUE (TRACER_DYNAMIC_COVERAGE);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment