summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog15
-rw-r--r--gcc/Makefile.in2
-rw-r--r--gcc/coverage.c31
-rw-r--r--gcc/gcov-io.h50
-rw-r--r--gcc/libgcov.c37
5 files changed, 123 insertions, 12 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 98fcabc6a0a..4830beadad9 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,18 @@
+2003-05-04 Zdenek Dvorak <rakdver@atrey.karlin.mff.cuni.cz>
+
+ * Makefile.in (LIBGCOV): Add _gcov_merge_add.
+ * gcov-io.h: Make GCOV_LINKAGE extern in libgcov and prevent resulting
+ namespace clash.
+ (GCOV_MERGE_FUNCTIONS): New.
+ (gcov_merge_fn): Declare.
+ (struct gcov_ctr_info): New field "merge".
+ (__gcov_merge_add): Declare.
+ * coverage.c (ctr_merge_functions): New.
+ (build_ctr_info_type, build_ctr_info_value): Initialize merge field
+ of gcov_ctr_info type.
+ * libgcov.c (__gcov_merge_add): New.
+ (gcov_exit): Call a hook to merge values of counters.
+
2003-05-04 Gabriel Dos Reis <gdr@integrable-solutions.net>
* toplev.h (pedwarn_with_file_and_line): Don't declare.
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index e99dbb9646d..70df3eadfe6 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -854,7 +854,7 @@ STAGESTUFF = *$(objext) insn-flags.h insn-config.h insn-codes.h \
LIB2FUNCS_ST = _eprintf __gcc_bcmp
# Defined in libgcov.c, included only in gcov library
-LIBGCOV = _gcov
+LIBGCOV = _gcov _gcov_merge_add
FPBIT_FUNCS = _pack_sf _unpack_sf _addsub_sf _mul_sf _div_sf \
_fpcmp_parts_sf _compare_sf _eq_sf _ne_sf _gt_sf _ge_sf \
diff --git a/gcc/coverage.c b/gcc/coverage.c
index 6d8ae9a55fb..36400f32e9c 100644
--- a/gcc/coverage.c
+++ b/gcc/coverage.c
@@ -98,6 +98,9 @@ static htab_t counts_hash = NULL;
/* The names of the counter tables. */
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;
+
/* Forward declarations. */
static hashval_t htab_counts_entry_hash PARAMS ((const void *));
static int htab_counts_entry_eq PARAMS ((const void *, const void *));
@@ -559,6 +562,7 @@ build_ctr_info_type ()
{
tree type = (*lang_hooks.types.make_type) (RECORD_TYPE);
tree field, fields = NULL_TREE;
+ tree gcov_merge_fn_type;
/* counters */
field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
@@ -571,6 +575,18 @@ build_ctr_info_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);
+ field = build_decl (FIELD_DECL, NULL_TREE,
+ build_pointer_type (gcov_merge_fn_type));
+ TREE_CHAIN (field) = fields;
+ fields = field;
+
finish_builtin_struct (type, "__gcov_ctr_info", fields, NULL_TREE);
return type;
@@ -587,6 +603,7 @@ build_ctr_info_value (counter, type)
{
tree value = NULL_TREE;
tree fields = TYPE_FIELDS (type);
+ tree fn;
/* counters */
value = tree_cons (fields,
@@ -614,6 +631,20 @@ build_ctr_info_value (counter, type)
}
else
value = tree_cons (fields, null_pointer_node, value);
+ fields = TREE_CHAIN (fields);
+
+ fn = build_decl (FUNCTION_DECL,
+ get_identifier (ctr_merge_functions[counter]),
+ TREE_TYPE (TREE_TYPE (fields)));
+ DECL_EXTERNAL (fn) = 1;
+ TREE_PUBLIC (fn) = 1;
+ DECL_ARTIFICIAL (fn) = 1;
+ TREE_NOTHROW (fn) = 1;
+ value = tree_cons (fields,
+ build1 (ADDR_EXPR,
+ TREE_TYPE (fields),
+ fn),
+ value);
value = build_constructor (type, nreverse (value));
diff --git a/gcc/gcov-io.h b/gcc/gcov-io.h
index df5fb976543..19b43aba35f 100644
--- a/gcc/gcov-io.h
+++ b/gcc/gcov-io.h
@@ -176,15 +176,46 @@ typedef HOST_WIDEST_INT gcov_type;
#endif
#endif
-/* In lib gcov we want function linkage to be static, so we do not
- polute the global namespace. In the compiler we want it extern, so
- that they can be accessed from elsewhere. */
-#if IN_LIBGCOV || IN_GCOV
+/* In gcov we want function linkage to be static, so we do not
+ polute the global namespace. In libgcov we need these functions
+ to be extern, so prefix them with __gcov so that we do not conflict.
+ In the compiler we want it extern, so that they can be accessed from
+ elsewhere. */
+#if IN_LIBGCOV
+
+#define GCOV_LINKAGE /* nothing */
+#define gcov_var __gcov_var
+#define gcov_open __gcov_open
+#define gcov_close __gcov_close
+#define gcov_write_bytes __gcov_write_bytes
+#define gcov_write_unsigned __gcov_write_unsigned
+#define gcov_write_counter __gcov_write_counter
+#define gcov_write_string __gcov_write_string
+#define gcov_write_tag __gcov_write_tag
+#define gcov_write_length __gcov_write_length
+#define gcov_write_summary __gcov_write_summary
+#define gcov_read_bytes __gcov_read_bytes
+#define gcov_read_unsigned __gcov_read_unsigned
+#define gcov_read_counter __gcov_read_counter
+#define gcov_read_string __gcov_read_string
+#define gcov_read_summary __gcov_read_summary
+#define gcov_position __gcov_position
+#define gcov_seek __gcov_seek
+#define gcov_seek_end __gcov_seek_end
+#define gcov_is_eof __gcov_is_eof
+#define gcov_is_error __gcov_is_error
+#define gcov_time __gcov_time
+
+#elif IN_GCOV
+
#define GCOV_LINKAGE static
-#else
+
+#else /* !IN_LIBGCOV && !IN_GCOV */
+
#ifndef GCOV_LINKAGE
#define GCOV_LINKAGE extern
#endif
+
#endif
/* File suffixes. */
@@ -220,6 +251,9 @@ typedef HOST_WIDEST_INT gcov_type;
/* A list of human readable names of the counters */
#define GCOV_COUNTER_NAMES {"arcs"}
+/* Names of merge functions for counters. */
+#define GCOV_MERGE_FUNCTIONS {"__gcov_merge_add"}
+
/* Convert a counter index to a tag. */
#define GCOV_TAG_FOR_COUNTER(COUNT) \
(GCOV_TAG_COUNTER_BASE + ((COUNT) << 17))
@@ -286,11 +320,15 @@ struct gcov_fn_info
unsigned n_ctrs[0]; /* instrumented counters */
};
+/* Type of function used to merge counters. */
+typedef void (*gcov_merge_fn) (gcov_type *, unsigned);
+
/* Information about counters. */
struct gcov_ctr_info
{
unsigned num; /* number of counters. */
gcov_type *values; /* their values. */
+ gcov_merge_fn merge; /* The function used to merge them. */
};
/* Information about a single object file. */
@@ -317,6 +355,8 @@ extern void __gcov_init (struct gcov_info *);
/* Called before fork, to avoid double counting. */
extern void __gcov_flush (void);
+/* The merge function that just sums the counters. */
+extern void __gcov_merge_add (gcov_type *, unsigned);
#endif /* IN_LIBGCOV */
/* Because small reads and writes, interspersed with seeks cause lots
diff --git a/gcc/libgcov.c b/gcc/libgcov.c
index a40611494fc..74e8fa123de 100644
--- a/gcc/libgcov.c
+++ b/gcc/libgcov.c
@@ -32,11 +32,19 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#if defined(inhibit_libc)
/* If libc and its header files are not available, provide dummy functions. */
+#ifdef L_gcov
void __gcov_init (void *p);
void __gcov_flush (void);
void __gcov_init (void *p) { }
void __gcov_flush (void) { }
+#endif
+
+#ifdef L_gcov_merge_add
+void __gcov_merge_add (gcov_type *, unsigned);
+
+void __gcov_merge_add (gcov_type *counters, unsigned n_counters) { }
+#endif
#else
@@ -59,6 +67,8 @@ void __gcov_flush (void) { }
#endif
#define IN_LIBGCOV 1
#include "gcov-io.h"
+
+#ifdef L_gcov
#include "gcov-io.c"
/* Chain of per-object gcov structures. */
@@ -227,7 +237,7 @@ gcov_exit (void)
if ((1 << t_ix) & gi_ptr->ctr_mask)
{
unsigned n_counts;
- gcov_type *c_ptr;
+ gcov_merge_fn merge;
tag = gcov_read_unsigned ();
length = gcov_read_unsigned ();
@@ -235,11 +245,10 @@ gcov_exit (void)
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;
+ n_counts = fi_ptr->n_ctrs[c_ix];
+ merge = gi_ptr->counts[c_ix].merge;
+ (*merge) (values[c_ix], n_counts);
+ values[c_ix] += n_counts;
c_ix++;
}
if ((error = gcov_is_error ()))
@@ -450,4 +459,20 @@ __gcov_flush (void)
}
}
+#endif /* L_gcov */
+
+#ifdef L_gcov_merge_add
+/* The profile merging function that just adds the counters. It is given
+ an array COUNTERS of N_COUNTERS old counters and it reads the same number
+ of counters from the gcov file. */
+void
+__gcov_merge_add (counters, n_counters)
+ gcov_type *counters;
+ unsigned n_counters;
+{
+ for (; n_counters; counters++, n_counters--)
+ *counters += gcov_read_counter ();
+}
+#endif /* L_gcov_merge_add */
+
#endif /* inhibit_libc */