OSDN Git Service

2003-06-10 Andrew Haley <aph@redhat.com>
[pf3gnuchains/gcc-fork.git] / gcc / coverage.c
index 36400f3..1b537c6 100644 (file)
@@ -72,17 +72,18 @@ typedef struct counts_entry
   
 } counts_entry_t;
 
-static unsigned fn_ident = 1;
 static struct function_list *functions_head = 0;
 static struct function_list **functions_tail = &functions_head;
+static unsigned no_coverage = 0;
 
 /* Cumulative counter information for whole program.  */
 static unsigned prg_ctr_mask; /* Mask of counter types generated.  */
-static unsigned prg_n_ctrs[GCOV_COUNTERS];
+static unsigned prg_n_ctrs[GCOV_COUNTERS]; /* Total counters allocated.  */
 
 /* Counter information for current function.  */
-static unsigned fn_ctr_mask;
-static unsigned fn_n_ctrs[GCOV_COUNTERS];
+static unsigned fn_ctr_mask; /* Mask of counters used. */
+static unsigned fn_n_ctrs[GCOV_COUNTERS]; /* Counters allocated.  */
+static unsigned fn_b_ctrs[GCOV_COUNTERS]; /* Allocation base.  */
 
 /* Name of the output file for coverage output file.  */
 static char *bbg_file_name;
@@ -99,7 +100,8 @@ static htab_t counts_hash = NULL;
 static GTY(()) rtx ctr_labels[GCOV_COUNTERS];
 
 /* The names of merge functions for counters.  */
-static const char *ctr_merge_functions[GCOV_COUNTERS] = GCOV_MERGE_FUNCTIONS;
+static const char *const ctr_merge_functions[GCOV_COUNTERS] = GCOV_MERGE_FUNCTIONS;
+static const char *const ctr_names[GCOV_COUNTERS] = GCOV_COUNTER_NAMES;
 
 /* Forward declarations.  */
 static hashval_t htab_counts_entry_hash PARAMS ((const void *));
@@ -151,11 +153,14 @@ htab_counts_entry_del (of)
 static void
 read_counts_file ()
 {
-  unsigned fn_ident = 0;
-  unsigned version, ix, checksum = -1;
+  gcov_unsigned_t fn_ident = 0;
+  gcov_unsigned_t version, checksum = -1;
+  unsigned ix;
   counts_entry_t *summaried = NULL;
   unsigned seen_summary = 0;
-  
+  gcov_unsigned_t tag;
+  int error = 0;
+
   if (!gcov_open (da_file_name, 1))
     return;
   
@@ -168,7 +173,7 @@ read_counts_file ()
   else if ((version = gcov_read_unsigned ()) != GCOV_VERSION)
     {
       char v[4], e[4];
-      unsigned required = GCOV_VERSION;
+      gcov_unsigned_t required = GCOV_VERSION;
       
       for (ix = 4; ix--; required >>= 8, version >>= 8)
        {
@@ -184,13 +189,11 @@ read_counts_file ()
   counts_hash = htab_create (10,
                             htab_counts_entry_hash, htab_counts_entry_eq,
                             htab_counts_entry_del);
-  while (!gcov_is_eof ())
+  while ((tag = gcov_read_unsigned ()))
     {
-      unsigned tag, length;
-      unsigned long offset;
-      int error;
+      gcov_unsigned_t length;
+      gcov_position_t offset;
       
-      tag = gcov_read_unsigned ();
       length = gcov_read_unsigned ();
       offset = gcov_position ();
       if (tag == GCOV_TAG_FUNCTION)
@@ -259,28 +262,38 @@ read_counts_file ()
              htab_delete (counts_hash);
              break;
            }
-         
-         /* This should always be true for a just allocated entry,
-            and always false for an existing one. Check this way, in
-            case the gcov file is corrupt.  */
-         if (!entry->chain || summaried != entry)
+         else if (elt.ctr >= GCOV_COUNTERS_SUMMABLE)
+           {
+             warning ("cannot merge separate %s counters for function %u",
+                      ctr_names[elt.ctr], fn_ident);
+             goto skip_merge;
+           }
+
+         if (elt.ctr < GCOV_COUNTERS_SUMMABLE
+             /* This should always be true for a just allocated entry,
+                and always false for an existing one. Check this way, in
+                case the gcov file is corrupt.  */
+             && (!entry->chain || summaried != entry))
            {
              entry->chain = summaried;
              summaried = entry;
            }
          for (ix = 0; ix != n_counts; ix++)
            entry->counts[ix] += gcov_read_counter ();
+       skip_merge:;
        }
-      gcov_seek (offset, length);
+      gcov_sync (offset, length);
       if ((error = gcov_is_error ()))
-       {
-         warning (error < 0 ? "`%s' has overflowed" : "`%s' is corrupted",
-                  da_file_name);
-         htab_delete (counts_hash);
-         break;
-       }
+       break;
     }
 
+  if (!gcov_is_eof ())
+    {
+      warning (error < 0 ? "`%s' has overflowed" : "`%s' is corrupted",
+              da_file_name);
+      htab_delete (counts_hash);
+    }
+  
   gcov_close ();
 }
 
@@ -303,7 +316,7 @@ get_coverage_counts (unsigned counter, unsigned expected,
       return NULL;
     }
 
-  elt.ident = fn_ident;
+  elt.ident = current_function_funcdef_no + 1;
   elt.ctr = counter;
   entry = htab_find (counts_hash, &elt);
   if (!entry)
@@ -327,14 +340,18 @@ get_coverage_counts (unsigned counter, unsigned expected,
   return entry->counts;
 }
 
-/* Generate a MEM rtl to access COUNTER NO .  */
+/* Allocate NUM counters of type COUNTER. Returns non-zero if the
+   allocation succeeded.  */
 
-rtx
-coverage_counter_ref (unsigned counter, unsigned no)
+int
+coverage_counter_alloc (unsigned counter, unsigned num)
 {
-  enum machine_mode mode = mode_for_size (GCOV_TYPE_SIZE, MODE_INT, 0);
-  rtx ref;
-
+  if (no_coverage)
+    return 0;
+  
+  if (!num)
+    return 1;
+  
   if (!ctr_labels[counter])
     {
       /* Generate and save a copy of this so it can be shared.  */
@@ -343,15 +360,25 @@ coverage_counter_ref (unsigned counter, unsigned no)
       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;
-    }
+  fn_b_ctrs[counter] = fn_n_ctrs[counter];
+  fn_n_ctrs[counter] += num;
+  fn_ctr_mask |= 1 << counter;
+  return 1;
+}
+
+/* Generate a MEM rtl to access COUNTER NO.  */
+
+rtx
+coverage_counter_ref (unsigned counter, unsigned no)
+{
+  unsigned gcov_size = tree_low_cst (TYPE_SIZE (GCOV_TYPE_NODE), 1);
+  enum machine_mode mode = mode_for_size (gcov_size, MODE_INT, 0);
+  rtx ref;
 
-  no += prg_n_ctrs[counter];
-  ref = plus_constant (ctr_labels[counter],
-                      GCOV_TYPE_SIZE / BITS_PER_UNIT * no);
+  if (no >= fn_n_ctrs[counter] - fn_b_ctrs[counter])
+    abort ();
+  no += prg_n_ctrs[counter] + fn_b_ctrs[counter];
+  ref = plus_constant (ctr_labels[counter], gcov_size / BITS_PER_UNIT * no);
   ref = gen_rtx_MEM (mode, ref);
   set_mem_alias_set (ref, new_alias_set ());
 
@@ -405,6 +432,9 @@ compute_checksum ()
 int
 coverage_begin_output ()
 {
+  if (no_coverage)
+    return 0;
+  
   if (!bbg_function_announced)
     {
       const char *file = DECL_SOURCE_FILE (current_function_decl);
@@ -425,7 +455,7 @@ coverage_begin_output ()
       
       /* Announce function */
       offset = gcov_write_tag (GCOV_TAG_FUNCTION);
-      gcov_write_unsigned (fn_ident);
+      gcov_write_unsigned (current_function_funcdef_no + 1);
       gcov_write_unsigned (compute_checksum ());
       gcov_write_string (IDENTIFIER_POINTER
                         (DECL_ASSEMBLER_NAME (current_function_decl)));
@@ -462,20 +492,18 @@ coverage_end_function ()
       functions_tail = &item->next;
        
       item->next = 0;
-      /* It would be nice to use the unique source location. */
-      item->ident = fn_ident;
+      item->ident = current_function_funcdef_no + 1;
       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;
+         fn_n_ctrs[i] = fn_b_ctrs[i] = 0;
        }
       prg_ctr_mask |= fn_ctr_mask;
       fn_ctr_mask = 0;
     }
   bbg_function_announced = 0;
-  fn_ident++;
 }
 
 /* Creates the gcov_fn_info RECORD_TYPE.  */
@@ -489,10 +517,10 @@ build_fn_info_type (counters)
   tree array_type;
   
   /* ident */
-  fields = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
+  fields = build_decl (FIELD_DECL, NULL_TREE, unsigned_intSI_type_node);
 
   /* checksum */
-  field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
+  field = build_decl (FIELD_DECL, NULL_TREE, unsigned_intSI_type_node);
   TREE_CHAIN (field) = fields;
   fields = field;
 
@@ -525,14 +553,14 @@ build_fn_info_value (function, type)
   
   /* ident */
   value = tree_cons (fields,
-                    convert (unsigned_type_node,
+                    convert (unsigned_intSI_type_node,
                              build_int_2 (function->ident, 0)),
                     value);
   fields = TREE_CHAIN (fields);
   
   /* checksum */
   value = tree_cons (fields,
-                    convert (unsigned_type_node,
+                    convert (unsigned_intSI_type_node,
                              build_int_2 (function->checksum, 0)),
                     value);
   fields = TREE_CHAIN (fields);
@@ -562,26 +590,24 @@ build_ctr_info_type ()
 {
   tree type = (*lang_hooks.types.make_type) (RECORD_TYPE);
   tree field, fields = NULL_TREE;
+  tree gcov_ptr_type = build_pointer_type (GCOV_TYPE_NODE);
   tree gcov_merge_fn_type;
-  
+
   /* counters */
-  field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
+  field = build_decl (FIELD_DECL, NULL_TREE, unsigned_intSI_type_node);
   TREE_CHAIN (field) = fields;
   fields = field;
 
   /* values */
-  field = build_decl (FIELD_DECL, NULL_TREE,
-                     build_pointer_type (make_signed_type (GCOV_TYPE_SIZE)));
+  field = build_decl (FIELD_DECL, NULL_TREE, gcov_ptr_type);
   TREE_CHAIN (field) = fields;
   fields = field;
 
   /* merge */
   gcov_merge_fn_type =
-       build_function_type_list (
-               void_type_node,
-               build_pointer_type (make_signed_type (GCOV_TYPE_SIZE)),
-               unsigned_type_node,
-               NULL_TREE);
+    build_function_type_list (void_type_node,
+                             gcov_ptr_type, unsigned_type_node,
+                             NULL_TREE);
   field = build_decl (FIELD_DECL, NULL_TREE,
                      build_pointer_type (gcov_merge_fn_type));
   TREE_CHAIN (field) = fields;
@@ -607,7 +633,7 @@ build_ctr_info_value (counter, type)
 
   /* counters */
   value = tree_cons (fields,
-                    convert (unsigned_type_node,
+                    convert (unsigned_intSI_type_node,
                              build_int_2 (prg_n_ctrs[counter], 0)),
                     value);
   fields = TREE_CHAIN (fields);
@@ -641,9 +667,7 @@ build_ctr_info_value (counter, type)
   DECL_ARTIFICIAL (fn) = 1;
   TREE_NOTHROW (fn) = 1;
   value = tree_cons (fields,
-                    build1 (ADDR_EXPR,
-                            TREE_TYPE (fields),
-                            fn),
+                    build1 (ADDR_EXPR, TREE_TYPE (fields), fn),
                     value);
 
   value = build_constructor (type, nreverse (value));
@@ -680,10 +704,10 @@ build_gcov_info ()
   const_type = build_qualified_type (type, TYPE_QUAL_CONST);
   
   /* Version ident */
-  field = build_decl (FIELD_DECL, NULL_TREE, long_unsigned_type_node);
+  field = build_decl (FIELD_DECL, NULL_TREE, unsigned_intSI_type_node);
   TREE_CHAIN (field) = fields;
   fields = field;
-  value = tree_cons (field, convert (long_unsigned_type_node,
+  value = tree_cons (field, convert (unsigned_intSI_type_node,
                                     build_int_2 (GCOV_VERSION, 0)),
                     value);
   
@@ -793,8 +817,9 @@ create_coverage ()
   char *ctor_name;
   tree ctor;
   rtx gcov_info_address;
-  int save_flag_inline_functions = flag_inline_functions;
 
+  no_coverage = 1; /* Disable any further coverage.  */
+  
   if (!prg_ctr_mask)
     return;
   
@@ -824,6 +849,7 @@ create_coverage ()
   TREE_PUBLIC (ctor) = ! targetm.have_ctors_dtors;
   TREE_USED (ctor) = 1;
   DECL_RESULT (ctor) = build_decl (RESULT_DECL, NULL_TREE, void_type_node);
+  DECL_UNINLINABLE (ctor) = 1;
 
   ctor = (*lang_hooks.decls.pushdecl) (ctor);
   rest_of_decl_compilation (ctor, 0, 1, 0);
@@ -834,7 +860,6 @@ create_coverage ()
   init_function_start (ctor, input_filename, input_line);
   (*lang_hooks.decls.pushlevel) (0);
   expand_function_start (ctor, 0);
-  cfun->arc_profile = 0;
 
   /* Actually generate the code to call __gcov_init.  */
   gcov_info_address = force_reg (Pmode, XEXP (DECL_RTL (gcov_info), 0));
@@ -844,16 +869,8 @@ create_coverage ()
   expand_function_end (input_filename, input_line, 0);
   (*lang_hooks.decls.poplevel) (1, 0, 1);
 
-  /* Since ctor isn't in the list of globals, it would never be emitted
-     when it's considered to be 'safe' for inlining, so turn off
-     flag_inline_functions.  */
-  flag_inline_functions = 0;
-
   rest_of_compilation (ctor);
 
-  /* Reset flag_inline_functions to its original value.  */
-  flag_inline_functions = save_flag_inline_functions;
-
   if (! quiet_flag)
     fflush (asm_out_file);
   current_function_decl = NULL_TREE;