===================================================================
@@ -8489,14 +8489,12 @@ dump_tree_statistics (void)
#define FILE_FUNCTION_FORMAT "_GLOBAL__%s_%s"
-/* Generate a crc32 of a string. */
+/* Generate a crc32 of a byte. */
unsigned
-crc32_string (unsigned chksum, const char *string)
+crc32_byte (unsigned chksum, char byte)
{
- do
- {
- unsigned value = *string << 24;
+ unsigned value = (unsigned) byte << 24;
unsigned ix;
for (ix = 8; ix--; value <<= 1)
@@ -8507,6 +8505,18 @@ crc32_string (unsigned chksum, const cha
chksum <<= 1;
chksum ^= feedback;
}
+ return chksum;
+}
+
+
+/* Generate a crc32 of a string. */
+
+unsigned
+crc32_string (unsigned chksum, const char *string)
+{
+ do
+ {
+ chksum = crc32_byte (chksum, *string);
}
while (*string++);
return chksum;
@@ -8530,8 +8540,10 @@ clean_symbol_name (char *p)
*p = '_';
}
-/* Generate a name for a special-purpose function function.
+/* Generate a name for a special-purpose function.
The generated name may need to be unique across the whole link.
+ Changes to this function may also require corresponding changes to
+ xstrdup_mask_random.
TYPE is some string to identify the purpose of this function to the
linker or collect2; it must start with an uppercase letter,
one of:
===================================================================
@@ -4948,6 +4948,7 @@ inlined_function_outer_scope_p (const_tr
/* In tree.c */
extern unsigned crc32_string (unsigned, const char *);
+extern unsigned crc32_byte (unsigned, char);
extern void clean_symbol_name (char *);
extern tree get_file_function_name (const char *);
extern tree get_callee_fndecl (const_tree);
===================================================================
@@ -54,6 +54,13 @@ along with Gcov; see the file COPYING3.
some places we make use of the knowledge of how profile.c works to
select particular algorithms here. */
+/* The code validates that the profile information read in corresponds
+ to the code currently being compiled. Rather than checking for
+ identical files, the code below computes a checksum on the CFG
+ (based on the order of basic blocks and the arcs in the CFG). If
+ the CFG checksum in the gcda file match the CFG checksum for the
+ code currently being compiled, the profile data will be used. */
+
/* This is the size of the buffer used to read in source file lines. */
#define STRING_SIZE 200
@@ -161,7 +168,8 @@ typedef struct function_info
/* Name of function. */
char *name;
unsigned ident;
- unsigned checksum;
+ unsigned lineno_checksum;
+ unsigned cfg_checksum;
/* Array of basic blocks. */
block_t *blocks;
@@ -809,12 +817,14 @@ read_graph_file (void)
if (tag == GCOV_TAG_FUNCTION)
{
char *function_name;
- unsigned ident, checksum, lineno;
+ unsigned ident, lineno;
+ unsigned lineno_checksum, cfg_checksum;
source_t *src;
function_t *probe, *prev;
ident = gcov_read_unsigned ();
- checksum = gcov_read_unsigned ();
+ lineno_checksum = gcov_read_unsigned ();
+ cfg_checksum = gcov_read_unsigned ();
function_name = xstrdup (gcov_read_string ());
src = find_source (gcov_read_string ());
lineno = gcov_read_unsigned ();
@@ -822,7 +832,8 @@ read_graph_file (void)
fn = XCNEW (function_t);
fn->name = function_name;
fn->ident = ident;
- fn->checksum = checksum;
+ fn->lineno_checksum = lineno_checksum;
+ fn->cfg_checksum = cfg_checksum;
fn->src = src;
fn->line = lineno;
@@ -1109,7 +1120,8 @@ read_count_file (void)
if (!fn)
;
- else if (gcov_read_unsigned () != fn->checksum)
+ else if (gcov_read_unsigned () != fn->lineno_checksum
+ || gcov_read_unsigned () != fn->cfg_checksum)
{
mismatch:;
fnotice (stderr, "%s:profile mismatch for '%s'\n",
===================================================================
@@ -103,7 +103,8 @@ see the files COPYING3 and COPYING.RUNTI
note: unit function-graph*
unit: header int32:checksum string:source
function-graph: announce_function basic_blocks {arcs | lines}*
- announce_function: header int32:ident int32:checksum
+ announce_function: header int32:ident
+ int32:lineno_checksum int32:cfg_checksum
string:name string:source int32:lineno
basic_block: header int32:flags*
arcs: header int32:block_no arc*
@@ -132,7 +133,8 @@ see the files COPYING3 and COPYING.RUNTI
data: {unit function-data* summary:object summary:program*}*
unit: header int32:checksum
function-data: announce_function arc_counts
- announce_function: header int32:ident int32:checksum
+ announce_function: header int32:ident
+ int32:lineno_checksum int32:cfg_checksum
arc_counts: header int64:count*
summary: int32:checksum {count-summary}GCOV_COUNTERS
count-summary: int32:num int32:runs int64:sum
@@ -330,7 +332,7 @@ typedef HOST_WIDEST_INT gcov_type;
file marker -- it is not required to be present. */
#define GCOV_TAG_FUNCTION ((gcov_unsigned_t)0x01000000)
-#define GCOV_TAG_FUNCTION_LENGTH (2)
+#define GCOV_TAG_FUNCTION_LENGTH (3)
#define GCOV_TAG_BLOCKS ((gcov_unsigned_t)0x01410000)
#define GCOV_TAG_BLOCKS_LENGTH(NUM) (NUM)
#define GCOV_TAG_BLOCKS_NUM(LENGTH) (LENGTH)
@@ -495,10 +497,12 @@ extern unsigned primary_module_id;
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
{
gcov_unsigned_t ident; /* unique ident of function */
- gcov_unsigned_t checksum; /* function checksum */
+ gcov_unsigned_t lineno_checksum; /* function lineo_checksum */
+ gcov_unsigned_t cfg_checksum; /* function cfg checksum */
gcov_unsigned_t dc_offset; /* direct call offset */
unsigned n_ctrs[0]; /* instrumented counters */
};
===================================================================
@@ -102,13 +102,6 @@ static int total_num_branches;
/* Forward declarations. */
static void find_spanning_tree (struct edge_list *);
-static unsigned instrument_edges (struct edge_list *);
-static void instrument_values (histogram_values);
-static void compute_branch_probabilities (void);
-static void compute_value_histograms (histogram_values);
-static gcov_type * get_exec_counts (void);
-static basic_block find_group (basic_block);
-static void union_groups (basic_block, basic_block);
/* Add edge instrumentation code to the entire insn chain.
@@ -238,10 +231,12 @@ instrument_values (histogram_values valu
}
-/* Computes hybrid profile for all matching entries in da_file. */
+/* Computes hybrid profile for all matching entries in da_file.
+
+ CFG_CHECKSUM is the precomputed checksum for the CFG. */
static gcov_type *
-get_exec_counts (void)
+get_exec_counts (unsigned cfg_checksum, unsigned lineno_checksum)
{
unsigned num_edges = 0;
basic_block bb;
@@ -258,7 +253,8 @@ get_exec_counts (void)
num_edges++;
}
- counts = get_coverage_counts (GCOV_COUNTER_ARCS, num_edges, &profile_info);
+ counts = get_coverage_counts (GCOV_COUNTER_ARCS, num_edges, cfg_checksum,
+ lineno_checksum, &profile_info);
if (!counts)
return NULL;
@@ -448,10 +444,12 @@ read_profile_edge_counts (gcov_type *exe
}
/* Compute the branch probabilities for the various branches.
- Annotate them accordingly. */
+ Annotate them accordingly.
+
+ CFG_CHECKSUM is the precomputed checksum for the CFG. */
static void
-compute_branch_probabilities (void)
+compute_branch_probabilities (unsigned cfg_checksum, unsigned lineno_checksum)
{
basic_block bb;
int i;
@@ -460,7 +458,7 @@ compute_branch_probabilities (void)
int passes;
int hist_br_prob[20];
int num_branches;
- gcov_type *exec_counts = get_exec_counts ();
+ gcov_type *exec_counts = get_exec_counts (cfg_checksum, lineno_checksum);
int inconsistent = 0;
/* Very simple sanity checks so we catch bugs in our profiling code. */
@@ -778,10 +776,13 @@ compute_branch_probabilities (void)
}
/* Load value histograms values whose description is stored in VALUES array
- from .gcda file. */
+ from .gcda file.
+
+ CFG_CHECKSUM is the precomputed checksum for the CFG. */
static void
-compute_value_histograms (histogram_values values)
+compute_value_histograms (histogram_values values, unsigned cfg_checksum,
+ unsigned lineno_checksum)
{
unsigned i, j, t, any;
unsigned n_histogram_counters[GCOV_N_VALUE_COUNTERS];
@@ -809,7 +810,8 @@ compute_value_histograms (histogram_valu
histogram_counts[t] =
get_coverage_counts (COUNTER_FOR_HIST_TYPE (t),
- n_histogram_counters[t], NULL);
+ n_histogram_counters[t], cfg_checksum,
+ lineno_checksum, NULL);
if (histogram_counts[t])
any = 1;
act_count[t] = histogram_counts[t];
@@ -912,6 +914,7 @@ branch_prob (void)
unsigned num_instrumented;
struct edge_list *el;
histogram_values values = NULL;
+ unsigned cfg_checksum, lineno_checksum;
total_num_times_called++;
@@ -1065,11 +1068,19 @@ branch_prob (void)
if (dump_file)
fprintf (dump_file, "%d ignored edges\n", ignored_edges);
+
+ /* Compute two different checksums. Note that we want to compute
+ the checksum in only once place, since it depends on the shape
+ of the control flow which can change during
+ various transformations. */
+ cfg_checksum = coverage_compute_cfg_checksum ();
+ lineno_checksum = coverage_compute_lineno_checksum ();
+
/* Write the data from which gcov can reconstruct the basic block
graph. */
/* Basic block flags */
- if (coverage_begin_output ())
+ if (coverage_begin_output (lineno_checksum, cfg_checksum))
{
gcov_position_t offset;
@@ -1086,7 +1097,7 @@ branch_prob (void)
EXIT_BLOCK_PTR->index = last_basic_block;
/* Arcs */
- if (coverage_begin_output ())
+ if (coverage_begin_output (lineno_checksum, cfg_checksum))
{
gcov_position_t offset;
@@ -1127,7 +1138,7 @@ branch_prob (void)
}
/* Line numbers. */
- if (coverage_begin_output ())
+ if (coverage_begin_output (lineno_checksum, cfg_checksum))
{
gcov_position_t offset;
@@ -1186,9 +1197,9 @@ branch_prob (void)
if (flag_branch_probabilities)
{
- compute_branch_probabilities ();
+ compute_branch_probabilities (cfg_checksum, lineno_checksum);
if (flag_profile_values)
- compute_value_histograms (values);
+ compute_value_histograms (values, cfg_checksum, lineno_checksum);
}
remove_fake_edges ();
@@ -1216,7 +1227,7 @@ branch_prob (void)
VEC_free (histogram_value, heap, values);
free_edge_list (el);
- coverage_end_function ();
+ coverage_end_function (lineno_checksum, cfg_checksum);
}
/* Union find algorithm implementation for the basic blocks using
@@ -1383,4 +1394,3 @@ end_branch_prob (void)
}
}
}
-
===================================================================
@@ -56,6 +56,7 @@ along with GCC; see the file COPYING3.
#include "intl.h"
#include "l-ipo.h"
+#include "gcov-io.h"
#include "gcov-io.c"
#include "params.h"
#include "dbgcnt.h"
@@ -65,7 +66,8 @@ struct function_list
{
struct function_list *next; /* next function */
unsigned ident; /* function ident */
- unsigned checksum; /* function checksum */
+ unsigned lineno_checksum; /* function lineno checksum */
+ unsigned cfg_checksum; /* function cfg checksum */
unsigned n_ctrs[GCOV_COUNTERS];/* number of counters. */
unsigned dc_offset; /* offset of counters to direct calls. */
};
@@ -85,7 +87,8 @@ typedef struct counts_entry
unsigned ctr;
/* Store */
- unsigned checksum;
+ unsigned lineno_checksum;
+ unsigned cfg_checksum;
gcov_type *counts;
struct gcov_ctr_summary summary;
@@ -148,8 +151,6 @@ static hashval_t htab_counts_entry_hash
static int htab_counts_entry_eq (const void *, const void *);
static void htab_counts_entry_del (void *);
static void read_counts_file (const char *, unsigned);
-static unsigned compute_checksum (void);
-static unsigned coverage_checksum_string (unsigned, const char *);
static tree build_fn_info_type (unsigned);
static tree build_fn_info_value (const struct function_list *, tree);
static tree build_ctr_info_type (void);
@@ -286,7 +287,6 @@ static void
read_counts_file (const char *da_file_name, unsigned module_id)
{
gcov_unsigned_t fn_ident = 0;
- gcov_unsigned_t checksum = -1;
counts_entry_t *summaried = NULL;
unsigned seen_summary = 0;
gcov_unsigned_t tag;
@@ -294,6 +294,8 @@ read_counts_file (const char *da_file_na
unsigned module_infos_read = 0;
struct pointer_set_t *modset = 0;
unsigned max_group = PARAM_VALUE (PARAM_MAX_LIPO_GROUP);
+ unsigned lineno_checksum = 0;
+ unsigned cfg_checksum = 0;
if (max_group == 0)
max_group = (unsigned) -1;
@@ -347,7 +349,8 @@ read_counts_file (const char *da_file_na
if (tag == GCOV_TAG_FUNCTION)
{
fn_ident = gcov_read_unsigned ();
- checksum = gcov_read_unsigned ();
+ lineno_checksum = gcov_read_unsigned ();
+ cfg_checksum = gcov_read_unsigned ();
if (seen_summary)
{
/* We have already seen a summary, this means that this
@@ -399,22 +402,24 @@ read_counts_file (const char *da_file_na
*slot = entry = XCNEW (counts_entry_t);
entry->ident = elt.ident;
entry->ctr = elt.ctr;
- entry->checksum = checksum;
+ entry->lineno_checksum = lineno_checksum;
+ entry->cfg_checksum = cfg_checksum;
entry->summary.num = n_counts;
entry->counts = XCNEWVEC (gcov_type, n_counts);
}
- else if (entry->checksum != checksum)
+ else if (entry->lineno_checksum != lineno_checksum
+ || entry->cfg_checksum != cfg_checksum)
{
- error ("coverage mismatch for function %u while reading execution counters",
- fn_ident);
- error ("checksum is %x instead of %x", entry->checksum, checksum);
+ error ("Profile data for function %u is corrupted", fn_ident);
+ error ("checksum is (%x,%x) instead of (%x,%x)",
+ entry->lineno_checksum, entry->cfg_checksum,
+ lineno_checksum, cfg_checksum);
htab_delete (counts_hash);
break;
}
else if (entry->summary.num != n_counts)
{
- error ("coverage mismatch for function %u while reading execution counters",
- fn_ident);
+ error ("Profile data for function %u is corrupted", fn_ident);
error ("number of counters is %d instead of %d", entry->summary.num, n_counts);
htab_delete (counts_hash);
break;
@@ -550,46 +555,14 @@ read_counts_file (const char *da_file_na
FUNC. EXPECTED is the number of expected counter entries. */
static counts_entry_t *
-get_coverage_counts_entry (struct function *func,
- unsigned counter, unsigned expected)
+get_coverage_counts_entry (struct function *func, unsigned counter)
{
- counts_entry_t *entry, *new_entry, elt;
- tree decl;
- struct cgraph_node *real_node;
+ counts_entry_t *entry, elt;
elt.ident = FUNC_DECL_GLOBAL_ID (func);
elt.ctr = counter;
entry = (counts_entry_t *) htab_find (counts_hash, &elt);
- if (entry)
- return entry;
-
- if (!L_IPO_COMP_MODE)
- return NULL;
- decl = func->decl;
- real_node = cgraph_lipo_get_resolved_node_1 (decl, false);
- if (real_node && 0)
- {
- counts_entry_t real_elt;
- real_elt.ident = FUNC_DECL_GLOBAL_ID (DECL_STRUCT_FUNCTION (real_node->decl));
- real_elt.ctr = counter;
- entry = (counts_entry_t *) htab_find (counts_hash, &real_elt);
- if (entry && expected == entry->summary.num)
- {
- /* Make a copy. */
- counts_entry_t **slot;
- slot = (counts_entry_t **) htab_find_slot (counts_hash, &elt, INSERT);
- gcc_assert (slot && !*slot);
- *slot = new_entry = XCNEW (counts_entry_t);
- new_entry->ident = elt.ident;
- new_entry->ctr = elt.ctr;
- new_entry->checksum = entry->checksum;
- new_entry->summary.num = entry->summary.num;
- new_entry->counts = XCNEWVEC (gcov_type, entry->summary.num);
- memcpy (new_entry->counts, entry->counts, sizeof (gcov_type) * entry->summary.num);
- entry = new_entry;
- }
- }
return entry;
}
@@ -597,10 +570,10 @@ get_coverage_counts_entry (struct functi
gcov_type *
get_coverage_counts (unsigned counter, unsigned expected,
+ unsigned cfg_checksum, unsigned lineno_checksum,
const struct gcov_ctr_summary **summary)
{
counts_entry_t *entry;
- gcov_unsigned_t checksum = -1;
/* No hash table, no counts. */
if (!counts_hash)
@@ -615,7 +588,7 @@ get_coverage_counts (unsigned counter, u
return NULL;
}
- entry = get_coverage_counts_entry (cfun, counter, expected);
+ entry = get_coverage_counts_entry (cfun, counter);
if (!entry)
{
@@ -625,26 +598,21 @@ get_coverage_counts (unsigned counter, u
return NULL;
}
- checksum = compute_checksum ();
- if (entry->checksum != checksum
+ if (entry->cfg_checksum != cfg_checksum
|| entry->summary.num != expected)
{
static int warned = 0;
bool warning_printed = false;
tree id = DECL_ASSEMBLER_NAME (current_function_decl);
- warning_printed =
- warning_at (input_location, OPT_Wcoverage_mismatch,
- "coverage mismatch for function "
- "%qE while reading counter %qs", id, ctr_names[counter]);
+ warning_printed =
+ warning_at (input_location, OPT_Wcoverage_mismatch,
+ "The control flow of function %qE does not match "
+ "its profile data (counter %qs)", id, ctr_names[counter]);
if (warning_printed)
{
- if (entry->checksum != checksum)
- inform (input_location, "checksum is %x instead of %x",
- entry->checksum, checksum);
- else
- inform (input_location, "number of counters is %d instead of %d",
- entry->summary.num, expected);
+ inform (input_location, "Use -Wno-error=coverage-mismatch to tolerate "
+ "the mismatch but performance may drop if the function is hot");
if (!seen_error ()
&& !warned++)
@@ -661,6 +629,12 @@ get_coverage_counts (unsigned counter, u
return NULL;
}
+ else if (entry->lineno_checksum != lineno_checksum)
+ {
+ warning (0, "Source location for function %qE have changed,"
+ " the profile data may be out of date",
+ DECL_ASSEMBLER_NAME (current_function_decl));
+ }
if (summary)
*summary = &entry->summary;
@@ -762,6 +736,7 @@ tree_coverage_counter_addr (unsigned cou
NULL, NULL));
}
+
/* Generate a checksum for a string. CHKSUM is the current
checksum. */
@@ -825,8 +800,8 @@ coverage_checksum_string (unsigned chksu
/* Compute checksum for the current function. We generate a CRC32. */
-static unsigned
-compute_checksum (void)
+unsigned
+coverage_compute_lineno_checksum (void)
{
tree name;
expanded_location xloc
@@ -857,6 +832,36 @@ compute_checksum (void)
return chksum;
}
+
+/* Compute cfg checksum for the current function.
+ The checksum is calculated carefully so that
+ source code changes that doesn't affect the control flow graph
+ won't change the checksum.
+ This is to make the profile data useable across source code change.
+ The downside of this is that the compiler may use potentially
+ wrong profile data - that the source code change has non-trivial impact
+ on the validity of profile data (e.g. the reversed condition)
+ but the compiler won't detect the change and use the wrong profile data. */
+
+unsigned
+coverage_compute_cfg_checksum (void)
+{
+ basic_block bb;
+ unsigned chksum = n_basic_blocks;
+
+ FOR_EACH_BB (bb)
+ {
+ edge e;
+ edge_iterator ei;
+ chksum = crc32_byte (chksum, bb->index);
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ {
+ chksum = crc32_byte (chksum, e->dest->index);
+ }
+ }
+
+ return chksum;
+}
/* Begin output to the graph file for the current function.
Opens the output file, if not already done. Writes the
@@ -864,7 +869,7 @@ compute_checksum (void)
should be output. */
int
-coverage_begin_output (void)
+coverage_begin_output (unsigned lineno_checksum, unsigned cfg_checksum)
{
/* We don't need to output .gcno file unless we're under -ftest-coverage
(e.g. -fprofile-arcs/generate/use don't need .gcno to work). */
@@ -890,12 +895,14 @@ coverage_begin_output (void)
bbg_file_opened = 1;
}
+
/* Announce function */
offset = gcov_write_tag (GCOV_TAG_FUNCTION);
gcov_write_unsigned (FUNC_DECL_FUNC_ID (cfun));
- gcov_write_unsigned (compute_checksum ());
+ gcov_write_unsigned (lineno_checksum);
+ gcov_write_unsigned (cfg_checksum);
gcov_write_string (IDENTIFIER_POINTER
- (DECL_ASSEMBLER_NAME (current_function_decl)));
+ (DECL_ASSEMBLER_NAME (current_function_decl)));
gcov_write_string (xloc.file);
gcov_write_unsigned (xloc.line);
gcov_write_length (offset);
@@ -909,7 +916,7 @@ coverage_begin_output (void)
error has occurred. Save function coverage counts. */
void
-coverage_end_function (void)
+coverage_end_function (unsigned lineno_checksum, unsigned cfg_checksum)
{
unsigned i;
@@ -928,9 +935,11 @@ coverage_end_function (void)
*functions_tail = item;
functions_tail = &item->next;
+
item->next = 0;
item->ident = FUNC_DECL_FUNC_ID (cfun);
- item->checksum = compute_checksum ();
+ item->lineno_checksum = lineno_checksum;
+ item->cfg_checksum = cfg_checksum;
for (i = 0; i != GCOV_COUNTERS; i++)
{
item->n_ctrs[i] = fn_n_ctrs[i];
@@ -978,7 +987,8 @@ coverage_dc_end_function (void)
functions_tail = &item->next;
item->next = 0;
item->ident = FUNC_DECL_FUNC_ID (cfun);
- item->checksum = compute_checksum ();
+ item->lineno_checksum = coverage_compute_lineno_checksum ();
+ item->cfg_checksum = coverage_compute_cfg_checksum ();
for (i = 0; i < GCOV_COUNTERS; i++)
item->n_ctrs[i] = 0;
}
@@ -1005,13 +1015,18 @@ build_fn_info_type (unsigned int counter
/* ident */
fields = build_decl (BUILTINS_LOCATION,
FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ());
-
- /* checksum */
+ /* lineno_checksum */
field = build_decl (BUILTINS_LOCATION,
FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ());
DECL_CHAIN (field) = fields;
fields = field;
+ /* cfg checksum */
+ field = build_decl (BUILTINS_LOCATION,
+ FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ());
+ DECL_CHAIN (field) = fields;
+ fields = field;
+
/* dc offset */
field = build_decl (BUILTINS_LOCATION,
FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ());
@@ -1051,10 +1066,16 @@ build_fn_info_value (const struct functi
function->ident));
fields = DECL_CHAIN (fields);
- /* checksum */
+ /* lineno_checksum */
+ CONSTRUCTOR_APPEND_ELT (v1, fields,
+ build_int_cstu (get_gcov_unsigned_t (),
+ function->lineno_checksum));
+ fields = DECL_CHAIN (fields);
+
+ /* cfg_checksum */
CONSTRUCTOR_APPEND_ELT (v1, fields,
build_int_cstu (get_gcov_unsigned_t (),
- function->checksum));
+ function->cfg_checksum));
fields = DECL_CHAIN (fields);
/* dc offset */
===================================================================
@@ -28,11 +28,17 @@ extern void coverage_finish (void);
/* Complete the coverage information for the current function. Once
per function. */
-extern void coverage_end_function (void);
+extern void coverage_end_function (unsigned, unsigned);
/* Start outputting coverage information for the current
function. Repeatable per function. */
-extern int coverage_begin_output (void);
+extern int coverage_begin_output (unsigned, unsigned);
+
+/* Compute the control flow checksum for the current function. */
+extern unsigned coverage_compute_cfg_checksum (void);
+
+/* Compute the line number checksum for the current function. */
+extern unsigned coverage_compute_lineno_checksum (void);
/* Allocate some counters. Repeatable per function. */
extern int coverage_counter_alloc (unsigned /*counter*/, unsigned/*num*/);
@@ -44,6 +50,8 @@ extern tree tree_coverage_counter_addr (
/* Get all the counters for the current function. */
extern gcov_type *get_coverage_counts (unsigned /*counter*/,
unsigned /*expected*/,
+ unsigned /*cfg_checksum*/,
+ unsigned /*lineno_checksum*/,
const struct gcov_ctr_summary **);
/* Get all the counters for the current function without warning. */
extern gcov_type *get_coverage_counts_no_warn (struct function *,
===================================================================
@@ -46,6 +46,8 @@ along with GCC; see the file COPYING3.
#include "output.h"
#include "l-ipo.h"
#include "profile.h"
+#include "target.h"
+#include "output.h"
static GTY(()) tree gcov_type_node;
static GTY(()) tree gcov_type_tmp_var;
@@ -92,8 +94,9 @@ init_ic_make_global_vars (void)
ptr_void);
TREE_PUBLIC (ic_void_ptr_var) = 1;
DECL_EXTERNAL (ic_void_ptr_var) = 1;
- DECL_TLS_MODEL (ic_void_ptr_var) =
- decl_default_tls_model (ic_void_ptr_var);
+ if (targetm.have_tls)
+ DECL_TLS_MODEL (ic_void_ptr_var) =
+ decl_default_tls_model (ic_void_ptr_var);
gcov_type_ptr = build_pointer_type (get_gcov_type ());
ic_gcov_type_ptr_var
@@ -102,8 +105,9 @@ init_ic_make_global_vars (void)
gcov_type_ptr);
TREE_PUBLIC (ic_gcov_type_ptr_var) = 1;
DECL_EXTERNAL (ic_gcov_type_ptr_var) = 1;
- DECL_TLS_MODEL (ic_gcov_type_ptr_var) =
- decl_default_tls_model (ic_gcov_type_ptr_var);
+ if (targetm.have_tls)
+ DECL_TLS_MODEL (ic_gcov_type_ptr_var) =
+ decl_default_tls_model (ic_gcov_type_ptr_var);
}
else
{
@@ -114,6 +118,9 @@ init_ic_make_global_vars (void)
TREE_STATIC (ic_void_ptr_var) = 1;
TREE_PUBLIC (ic_void_ptr_var) = 0;
DECL_INITIAL (ic_void_ptr_var) = NULL;
+ if (targetm.have_tls)
+ DECL_TLS_MODEL (ic_void_ptr_var) =
+ decl_default_tls_model (ic_void_ptr_var);
gcov_type_ptr = build_pointer_type (get_gcov_type ());
ic_gcov_type_ptr_var
@@ -123,6 +130,9 @@ init_ic_make_global_vars (void)
TREE_STATIC (ic_gcov_type_ptr_var) = 1;
TREE_PUBLIC (ic_gcov_type_ptr_var) = 0;
DECL_INITIAL (ic_gcov_type_ptr_var) = NULL;
+ if (targetm.have_tls)
+ DECL_TLS_MODEL (ic_gcov_type_ptr_var) =
+ decl_default_tls_model (ic_gcov_type_ptr_var);
}
DECL_ARTIFICIAL (ic_void_ptr_var) = 1;
===================================================================
@@ -1770,8 +1770,9 @@ promote_static_var_func (unsigned module
{
TREE_STATIC (decl) = 0;
DECL_EXTERNAL (decl) = 1;
- DECL_INITIAL (decl) = 0;
- DECL_CONTEXT (decl) = 0;
+ /* Keep the initializer to allow const prop. */
+ /* DECL_INITIAL (decl) = 0; */
+ DECL_CONTEXT (decl) = 0;
}
/* else
Function body will be deleted later before expansion. */
@@ -1800,7 +1801,8 @@ process_module_scope_static_var (struct
{
DECL_EXTERNAL (decl) = 1;
TREE_STATIC (decl) = 0;
- DECL_INITIAL (decl) = NULL;
+ /* Keep the initializer to allow const prop. */
+ /* DECL_INITIAL (decl) = NULL; */
if (DECL_CONTEXT (decl))
{
DECL_ASSEMBLER_NAME (decl);
===================================================================
@@ -507,9 +507,10 @@ gcov_exit (void)
/* Check function. */
if (tag != GCOV_TAG_FUNCTION
- || length != GCOV_TAG_FUNCTION_LENGTH
+ || length != GCOV_TAG_FUNCTION_LENGTH
|| gcov_read_unsigned () != fi_ptr->ident
- || gcov_read_unsigned () != fi_ptr->checksum)
+ || gcov_read_unsigned () != fi_ptr->lineno_checksum
+ || gcov_read_unsigned () != fi_ptr->cfg_checksum)
{
read_mismatch:;
fprintf (stderr, "profiling:%s:Merge mismatch for %s\n",
@@ -652,7 +653,8 @@ gcov_exit (void)
/* Announce function. */
gcov_write_tag_length (GCOV_TAG_FUNCTION, GCOV_TAG_FUNCTION_LENGTH);
gcov_write_unsigned (fi_ptr->ident);
- gcov_write_unsigned (fi_ptr->checksum);
+ gcov_write_unsigned (fi_ptr->lineno_checksum);
+ gcov_write_unsigned (fi_ptr->cfg_checksum);
c_ix = 0;
for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
===================================================================
@@ -328,7 +328,8 @@ tag_function (const char *filename ATTRI
unsigned long pos = gcov_position ();
printf (" ident=%u", gcov_read_unsigned ());
- printf (", checksum=0x%08x", gcov_read_unsigned ());
+ printf (", lineno_checksum=0x%08x", gcov_read_unsigned ());
+ printf (", cfg_checksum_checksum=0x%08x", gcov_read_unsigned ());
if (gcov_position () - pos < length)
{
const char *name;