From ab6a34f2f7b7c7505a1feeeabdf1d87329eb8878 Mon Sep 17 00:00:00 2001 From: nathan Date: Wed, 23 Apr 2003 14:05:11 +0000 Subject: * 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@65990 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 74 +++++ gcc/Makefile.in | 4 +- gcc/basic-block.h | 4 + gcc/coverage.c | 841 +++++++++++++++++++----------------------------------- gcc/coverage.h | 44 +-- gcc/gcov-dump.c | 41 +-- gcc/gcov-io.c | 32 ++- gcc/gcov-io.h | 89 +++--- gcc/gcov.c | 8 +- gcc/libgcov.c | 420 +++++++++++++-------------- gcc/mklibgcc.in | 2 +- gcc/predict.c | 21 +- gcc/profile.c | 38 +-- gcc/tracer.c | 4 +- 14 files changed, 698 insertions(+), 924 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ce228651954..0c18f2f0712 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,77 @@ +2003-04-23 Nathan Sidwell + + * 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 PR optimization/10339 diff --git a/gcc/Makefile.in b/gcc/Makefile.in index b8a6bb0b1cd..d82f5b009ed 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 fce7de55c8d..4c8d5e34dec 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 07c56a3ffc7..421b3b1a04e 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 f6ead44a597..8817b803816 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 fd9d1228467..5c0dd3a3676 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 94002a9c42b..b5952174517 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 d2beb1bbf2f..7f881999779 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 8a413677993..572292364b2 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 237da2d39e3..a2c831e8198 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 7407851ae9e..9cf67ccd67e 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 9bc77512e51..80ad41e1c99 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 3472bd05d9c..6a5548b47a9 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 1448670ddc6..701c16a9395 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); -- cgit v1.2.1