Makefile.in (LIBGCC_DEPS): Add gcov headers.
authorNathan Sidwell <nathan@codesourcery.com>
Wed, 23 Apr 2003 14:05:11 +0000 (14:05 +0000)
committerNathan Sidwell <nathan@gcc.gnu.org>
Wed, 23 Apr 2003 14:05:11 +0000 (14:05 +0000)
* 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

14 files changed:
gcc/ChangeLog
gcc/Makefile.in
gcc/basic-block.h
gcc/coverage.c
gcc/coverage.h
gcc/gcov-dump.c
gcc/gcov-io.c
gcc/gcov-io.h
gcc/gcov.c
gcc/libgcov.c
gcc/mklibgcc.in
gcc/predict.c
gcc/profile.c
gcc/tracer.c

index ce22865..0c18f2f 100644 (file)
@@ -1,3 +1,77 @@
+2003-04-23  Nathan Sidwell  <nathan@codesourcery.com>
+
+       * Makefile.in (LIBGCC_DEPS): Add gcov headers.
+       (libgcov.a): Depends on LIBGCC_DEPS.
+       * basic-block.h (profile_info): Moved here from coverage.h. Made
+       a pointer.
+       * coverage.c (struct function_list): Fixed array of counter types.
+       (struct counts_entry): Keyed by counter type, contains summary.
+       (profile_info): Moved to profile.c.
+       (prg_ctr_mask, prg_n_ctrs, fn_ctr_mask, fn_n_ctrs): New global
+       vars.
+       (profiler_label): Remove.
+       (ctr_labels): New.
+       (set_purpose, label_for_tag, build_counter_section_fields,
+       build_counter_section_value, build_counter_section_data_fields,
+       build_counter_section_data_values, build_function_info_fields,
+       build_function_info_value, gcov_info_fields, gcov_info_value): Remove.
+       (build_fn_info_type, build_fn_info_value, build_ctr_info_type,
+       build_ctr_info_value, build_gcov_info): New.
+       (htab_counts_entry_hash, htab_counts_entry_eq): Adjust.
+       (reads_counts_file): Adjust.
+       (get_coverage_counts): Takes counter number. Add summary
+       parameter. Adjust.
+       (coverage_counter_ref): Tkaes counter number. Adjust. Lazily
+       create counter array labels.
+       (coverage_end_function): Adjust.
+       (create_coverage): Adjust.
+       (find_counters_section): Remove.
+       * coverage.h (MAX_COUNTER_SECTIONS): Remove.
+       (struct section_info, struct profile_info): Remove.
+       (profile_info): Moved to basic-block.h.
+       (coverage_counter_ref): Takes a counter number.
+       (get_coverage_counts): Takes a counter number. Added summary
+       parameter.
+       (find_counters_section): Remove.
+       * gcov-dump.c (tag_arc_counts): Rename to ...
+       (tag_counters): ... here. Adjust.
+       (tag_table): Move tag_counters to 3rd entry. Remove
+       PROGRAM_PLACEHOLDER and PROGRAM_INCORRECT entries.
+       (dump_file): Check for counter tag values here.
+       (tag_summary): Adjust.
+       * gcov-io.c (gcov_write_summary, gcov_read_summary): Adjust.
+       * gcov-io.h (GCOV_LOCKED): New.
+       (GCOV_TAG_ARC_COUNTS): Rename to ...
+       (GCOV_TAG_COUNTS_BASE): ... here.
+       (GCOV_TAG_PLACEHOLDER_SUMMARY, GCOV_TAG_INCORRECT_SUMMARY):
+       Remove.
+       (GCOV_COUNTER_ARCS, GCOV_COUNTERS, GCOV_NAMES): New.
+       (GCOV_TAG_FOR_COUNTER, GCOV_COUNTER_FOR_TAG,
+       GCOV_TAG_IS_COUNTER): New.
+       (struct gcov_ctr_summary): New.
+       (struct gcov_summary): Adjust.
+       (struct gcov_counter_section): Remove.
+       struct gcov_counter_section_data): Remove.
+       (struct gcov_function_info): Rename to ...
+       (struct gcov_fn_info): ... here. Adjust.
+       (struct gcov_ctr_info): New.
+       (struct gcov_info): Adjust.
+       * gcov.c (read_count_file): Adjust.
+       (output_lines): Adjust.
+       * libgcov.c (gcov_exit): Adjust.
+       (__gcov_flush): Adjust.
+       * mklibgcc.in (libgcc2_c_dep): Add gcov headers.
+       * predict.c (maybe_hot_bb_p, probably_cold_bb_p,
+       probably_never_executed_bb_p, compute_frequency_function): Adjust
+       profile_info use.
+       * profile.c (struct counts_entry): Remove.
+       (profile_info): Define here.
+       (get_exec_counts): Adjust get_coverage_counts call.
+       (compute_branch_probablilities): Remove find_counters_section
+       call.
+       (gen_edge_profiler): Adjust coverage_counter_ref call.
+       * tracer.c (tail_duplicate): Adjust profile_info use.
+
 2003-04-23  Roger Sayle  <roger@eyesopen.com>
 
        PR optimization/10339
index b8a6bb0..d82f5b0 100644 (file)
@@ -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)" \
index fce7de5..4c8d5e3 100644 (file)
@@ -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;
index 07c56a3..421b3b1 100644 (file)
@@ -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));
 
 \f
@@ -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;
+}
 \f
 /* 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);
 }
 \f
-/* 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;
-}
-
-\f
 /* Perform file-level initialization. Read in data file, generate name
    of graph file. */
 
@@ -1142,5 +890,4 @@ coverage_finish ()
     }
 }
 
-
 #include "gt-coverage.h"
index f6ead44..8817b80 100644 (file)
@@ -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
index fd9d122..5c0dd3a 100644 (file)
@@ -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);
+    }
 }
index 94002a9..b595217 100644 (file)
@@ -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.  */
 
index d2beb1b..7f88199 100644 (file)
@@ -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.  */
index 8a41367..5722923 100644 (file)
@@ -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");
index 237da2d..a2c831e 100644 (file)
@@ -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++;
+         }
     }
 }
 
index 7407851..9cf67cc 100644 (file)
@@ -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'
index 9bc7751..80ad41e 100644 (file)
@@ -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)
index 3472bd0..6a5548b 100644 (file)
@@ -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;
index 1448670..701c16a 100644 (file)
@@ -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);