X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fcoverage.c;h=24e0e3d87f2ac3b1553b030468b7561469b56d07;hb=adca58cae4bb9115a0dc5f7900c86a55b0c26460;hp=0973d4ad8867e246ef4d31acd56aca308c85688b;hpb=978b9403a08e35ee6d83abf428bf97dba0ef99f7;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/coverage.c b/gcc/coverage.c index 0973d4ad886..24e0e3d87f2 100644 --- a/gcc/coverage.c +++ b/gcc/coverage.c @@ -1,6 +1,7 @@ /* Read and write coverage files, and associated functionality. Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, 1999, - 2000, 2001, 2003, 2004, 2005 Free Software Foundation, Inc. + 2000, 2001, 2003, 2004, 2005, 2007, 2008, 2009, 2010 + Free Software Foundation, Inc. Contributed by James E. Wilson, UC Berkeley/Cygnus Support; based on some ideas from Dain Samples of UC Berkeley. Further mangling by Bob Manson, Cygnus Support. @@ -10,7 +11,7 @@ This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later +Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY @@ -19,9 +20,8 @@ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ +along with GCC; see the file COPYING3. If not see +. */ #define GCOV_LINKAGE @@ -37,21 +37,29 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "regs.h" #include "expr.h" #include "function.h" +#include "basic-block.h" #include "toplev.h" +#include "tm_p.h" #include "ggc.h" #include "coverage.h" #include "langhooks.h" #include "hashtab.h" #include "tree-iterator.h" #include "cgraph.h" +#include "tree-pass.h" +#include "diagnostic-core.h" +#include "intl.h" +#include "filenames.h" +#include "gcov-io.h" #include "gcov-io.c" 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. */ }; @@ -63,7 +71,8 @@ typedef struct counts_entry unsigned ctr; /* Store */ - unsigned checksum; + unsigned lineno_checksum; + unsigned cfg_checksum; gcov_type *counts; struct gcov_ctr_summary summary; @@ -99,10 +108,6 @@ static htab_t counts_hash = NULL; /* Trees representing the counter table arrays. */ static GTY(()) tree tree_ctr_tables[GCOV_COUNTERS]; -/* The names of the counter tables. Not used if we're - generating counters at tree level. */ -static GTY(()) rtx ctr_labels[GCOV_COUNTERS]; - /* The names of merge functions for counters. */ static const char *const ctr_merge_functions[GCOV_COUNTERS] = GCOV_MERGE_FUNCTIONS; static const char *const ctr_names[GCOV_COUNTERS] = GCOV_COUNTER_NAMES; @@ -112,8 +117,6 @@ static hashval_t htab_counts_entry_hash (const void *); static int htab_counts_entry_eq (const void *, const void *); static void htab_counts_entry_del (void *); static void read_counts_file (void); -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); @@ -140,7 +143,7 @@ get_gcov_unsigned_t (void) static hashval_t htab_counts_entry_hash (const void *of) { - const counts_entry_t *entry = of; + const counts_entry_t *const entry = (const counts_entry_t *) of; return entry->ident * GCOV_COUNTERS + entry->ctr; } @@ -148,8 +151,8 @@ htab_counts_entry_hash (const void *of) static int htab_counts_entry_eq (const void *of1, const void *of2) { - const counts_entry_t *entry1 = of1; - const counts_entry_t *entry2 = of2; + const counts_entry_t *const entry1 = (const counts_entry_t *) of1; + const counts_entry_t *const entry2 = (const counts_entry_t *) of2; return entry1->ident == entry2->ident && entry1->ctr == entry2->ctr; } @@ -157,7 +160,7 @@ htab_counts_entry_eq (const void *of1, const void *of2) static void htab_counts_entry_del (void *of) { - counts_entry_t *entry = of; + counts_entry_t *const entry = (counts_entry_t *) of; free (entry->counts); free (entry); @@ -169,11 +172,12 @@ static void read_counts_file (void) { gcov_unsigned_t fn_ident = 0; - gcov_unsigned_t checksum = -1; counts_entry_t *summaried = NULL; unsigned seen_summary = 0; gcov_unsigned_t tag; int is_error = 0; + unsigned lineno_checksum = 0; + unsigned cfg_checksum = 0; if (!gcov_open (da_file_name, 1)) return; @@ -199,7 +203,7 @@ read_counts_file (void) /* Read and discard the stamp. */ gcov_read_unsigned (); - + counts_hash = htab_create (10, htab_counts_entry_hash, htab_counts_entry_eq, htab_counts_entry_del); @@ -213,7 +217,8 @@ read_counts_file (void) 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 @@ -262,25 +267,27 @@ read_counts_file (void) entry = *slot; if (!entry) { - *slot = entry = xcalloc (1, sizeof (counts_entry_t)); - entry->ident = elt.ident; + *slot = entry = XCNEW (counts_entry_t); + entry->ident = fn_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 = xcalloc (n_counts, sizeof (gcov_type)); + 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; @@ -322,10 +329,10 @@ read_counts_file (void) 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, elt; - gcov_unsigned_t checksum = -1; /* No hash table, no counts. */ if (!counts_hash) @@ -333,7 +340,7 @@ get_coverage_counts (unsigned counter, unsigned expected, static int warned = 0; if (!warned++) - inform ((flag_guess_branch_prob + inform (input_location, (flag_guess_branch_prob ? "file %s not found, execution counts estimated" : "file %s not found, execution counts assumed to be zero"), da_file_name); @@ -342,31 +349,51 @@ get_coverage_counts (unsigned counter, unsigned expected, elt.ident = current_function_funcdef_no + 1; elt.ctr = counter; - entry = htab_find (counts_hash, &elt); + entry = (counts_entry_t *) htab_find (counts_hash, &elt); if (!entry) { - warning (0, "no coverage for function %qs found.", IDENTIFIER_POINTER - (DECL_ASSEMBLER_NAME (current_function_decl))); - return 0; + warning (0, "no coverage for function %qE found", + DECL_ASSEMBLER_NAME (current_function_decl)); + return NULL; } - checksum = compute_checksum (); - if (entry->checksum != checksum) - { - error ("coverage mismatch for function %qs while reading counter %qs.", - IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl)), - ctr_names[counter]); - error ("checksum is %x instead of %x", entry->checksum, checksum); - return 0; - } - else if (entry->summary.num != expected) + if (entry->cfg_checksum != cfg_checksum + || entry->summary.num != expected) { - error ("coverage mismatch for function %qs while reading counter %qs.", - IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl)), - ctr_names[counter]); - error ("number of counters is %d instead of %d", entry->summary.num, expected); - return 0; + 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, + "The control flow of function %qE does not match " + "its profile data (counter %qs)", id, ctr_names[counter]); + if (warning_printed) + { + 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++) + { + inform (input_location, "coverage mismatch ignored"); + inform (input_location, flag_guess_branch_prob + ? G_("execution counts estimated") + : G_("execution counts assumed to be zero")); + if (!flag_guess_branch_prob) + inform (input_location, + "this can result in poorly optimized code"); + } + } + + 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; @@ -388,21 +415,23 @@ coverage_counter_alloc (unsigned counter, unsigned num) if (!tree_ctr_tables[counter]) { - /* Generate and save a copy of this so it can be shared. */ - /* We don't know the size yet; make it big enough that nobody - will make any clever transformation on it. */ + /* Generate and save a copy of this so it can be shared. Leave + the index type unspecified for now; it will be set after all + functions have been compiled. */ char buf[20]; tree gcov_type_node = get_gcov_type (); - tree domain_tree - = build_index_type (build_int_cst (NULL_TREE, 1000)); /* replaced later */ tree gcov_type_array_type - = build_array_type (gcov_type_node, domain_tree); + = build_array_type (gcov_type_node, NULL_TREE); tree_ctr_tables[counter] - = build_decl (VAR_DECL, NULL_TREE, gcov_type_array_type); + = build_decl (BUILTINS_LOCATION, + VAR_DECL, NULL_TREE, gcov_type_array_type); TREE_STATIC (tree_ctr_tables[counter]) = 1; ASM_GENERATE_INTERNAL_LABEL (buf, "LPBX", counter + 1); DECL_NAME (tree_ctr_tables[counter]) = get_identifier (buf); DECL_ALIGN (tree_ctr_tables[counter]) = TYPE_ALIGN (gcov_type_node); + + if (dump_file) + fprintf (dump_file, "Using data file %s\n", da_file_name); } fn_b_ctrs[counter] = fn_n_ctrs[counter]; fn_n_ctrs[counter] += num; @@ -410,52 +439,41 @@ coverage_counter_alloc (unsigned counter, unsigned num) return 1; } -/* Generate a MEM rtl to access COUNTER NO. */ +/* Generate a tree to access COUNTER NO. */ -rtx -rtl_coverage_counter_ref (unsigned counter, unsigned no) +tree +tree_coverage_counter_ref (unsigned counter, unsigned no) { - enum machine_mode mode = mode_for_size (GCOV_TYPE_SIZE, MODE_INT, 0); - rtx ref; + tree gcov_type_node = get_gcov_type (); gcc_assert (no < fn_n_ctrs[counter] - fn_b_ctrs[counter]); no += prg_n_ctrs[counter] + fn_b_ctrs[counter]; - if (!ctr_labels[counter]) - { - ctr_labels[counter] = gen_rtx_SYMBOL_REF (Pmode, - ggc_strdup (IDENTIFIER_POINTER (DECL_NAME - (tree_ctr_tables[counter])))); - SYMBOL_REF_FLAGS (ctr_labels[counter]) = SYMBOL_FLAG_LOCAL; - } - 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 ()); - MEM_NOTRAP_P (ref) = 1; - return ref; + /* "no" here is an array index, scaled to bytes later. */ + return build4 (ARRAY_REF, gcov_type_node, tree_ctr_tables[counter], + build_int_cst (integer_type_node, no), NULL, NULL); } -/* Generate a tree to access COUNTER NO. */ +/* Generate a tree to access the address of COUNTER NO. */ tree -tree_coverage_counter_ref (unsigned counter, unsigned no) +tree_coverage_counter_addr (unsigned counter, unsigned no) { tree gcov_type_node = get_gcov_type (); - tree domain_type = TYPE_DOMAIN (TREE_TYPE (tree_ctr_tables[counter])); gcc_assert (no < fn_n_ctrs[counter] - fn_b_ctrs[counter]); no += prg_n_ctrs[counter] + fn_b_ctrs[counter]; + TREE_ADDRESSABLE (tree_ctr_tables[counter]) = 1; + /* "no" here is an array index, scaled to bytes later. */ - return build4 (ARRAY_REF, gcov_type_node, tree_ctr_tables[counter], - fold_convert (domain_type, - build_int_cst (NULL_TREE, no)), - TYPE_MIN_VALUE (domain_type), - size_binop (EXACT_DIV_EXPR, TYPE_SIZE_UNIT (gcov_type_node), - size_int (TYPE_ALIGN_UNIT (gcov_type_node)))); + return build_fold_addr_expr (build4 (ARRAY_REF, gcov_type_node, + tree_ctr_tables[counter], + build_int_cst (integer_type_node, no), + NULL, NULL)); } + /* Generate a checksum for a string. CHKSUM is the current checksum. */ @@ -466,54 +484,60 @@ coverage_checksum_string (unsigned chksum, const char *string) char *dup = NULL; /* Look for everything that looks if it were produced by - get_file_function_name_long and zero out the second part + get_file_function_name and zero out the second part that may result from flag_random_seed. This is not critical as the checksums are used only for sanity checking. */ for (i = 0; string[i]; i++) { + int offset = 0; + if (!strncmp (string + i, "_GLOBAL__N_", 11)) + offset = 11; if (!strncmp (string + i, "_GLOBAL__", 9)) - for (i = i + 9; string[i]; i++) - if (string[i]=='_') - { - int y; - unsigned seed; - int scan; - - for (y = 1; y < 9; y++) - if (!(string[i + y] >= '0' && string[i + y] <= '9') - && !(string[i + y] >= 'A' && string[i + y] <= 'F')) - break; - if (y != 9 || string[i + 9] != '_') - continue; - for (y = 10; y < 18; y++) - if (!(string[i + y] >= '0' && string[i + y] <= '9') - && !(string[i + y] >= 'A' && string[i + y] <= 'F')) - break; - if (y != 18) - continue; - scan = sscanf (string + i + 10, "%X", &seed); - gcc_assert (scan); - if (seed != crc32_string (0, flag_random_seed)) - continue; - string = dup = xstrdup (string); - for (y = 10; y < 18; y++) - dup[i + y] = '0'; - break; - } - break; + offset = 9; + + /* C++ namespaces do have scheme: + _GLOBAL__N___functionname + since filename might contain extra underscores there seems + to be no better chance then walk all possible offsets looking + for magicnumber. */ + if (offset) + { + for (i = i + offset; string[i]; i++) + if (string[i]=='_') + { + int y; + + for (y = 1; y < 9; y++) + if (!(string[i + y] >= '0' && string[i + y] <= '9') + && !(string[i + y] >= 'A' && string[i + y] <= 'F')) + break; + if (y != 9 || string[i + 9] != '_') + continue; + for (y = 10; y < 18; y++) + if (!(string[i + y] >= '0' && string[i + y] <= '9') + && !(string[i + y] >= 'A' && string[i + y] <= 'F')) + break; + if (y != 18) + continue; + if (!dup) + string = dup = xstrdup (string); + for (y = 10; y < 18; y++) + dup[i + y] = '0'; + } + break; + } } chksum = crc32_string (chksum, string); - if (dup) - free (dup); + free (dup); return chksum; } /* Compute checksum for the current function. We generate a CRC32. */ -static unsigned -compute_checksum (void) +unsigned +coverage_compute_lineno_checksum (void) { expanded_location xloc = expand_location (DECL_SOURCE_LOCATION (current_function_decl)); @@ -525,6 +549,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 @@ -532,9 +586,11 @@ compute_checksum (void) should be output. */ int -coverage_begin_output (void) +coverage_begin_output (unsigned lineno_checksum, unsigned cfg_checksum) { - if (no_coverage) + /* 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). */ + if (no_coverage || !flag_test_coverage || flag_compare_debug) return 0; if (!bbg_function_announced) @@ -556,12 +612,14 @@ coverage_begin_output (void) bbg_file_opened = 1; } + /* Announce function */ offset = gcov_write_tag (GCOV_TAG_FUNCTION); gcov_write_unsigned (current_function_funcdef_no + 1); - 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); @@ -575,7 +633,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; @@ -589,14 +647,16 @@ coverage_end_function (void) { struct function_list *item; - item = xmalloc (sizeof (struct function_list)); + item = XCNEW (struct function_list); *functions_tail = item; functions_tail = &item->next; + item->next = 0; item->ident = current_function_funcdef_no + 1; - 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]; @@ -619,20 +679,27 @@ build_fn_info_type (unsigned int counters) tree array_type; /* ident */ - fields = build_decl (FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ()); + fields = build_decl (BUILTINS_LOCATION, + FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ()); + /* lineno_checksum */ + field = build_decl (BUILTINS_LOCATION, + FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ()); + DECL_CHAIN (field) = fields; + fields = field; - /* checksum */ - field = build_decl (FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ()); - TREE_CHAIN (field) = fields; + /* cfg checksum */ + field = build_decl (BUILTINS_LOCATION, + FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ()); + DECL_CHAIN (field) = fields; fields = field; - array_type = build_int_cst (NULL_TREE, counters - 1); - array_type = build_index_type (array_type); - array_type = build_array_type (unsigned_type_node, array_type); + array_type = build_index_type (size_int (counters - 1)); + array_type = build_array_type (get_gcov_unsigned_t (), array_type); /* counters */ - field = build_decl (FIELD_DECL, NULL_TREE, array_type); - TREE_CHAIN (field) = fields; + field = build_decl (BUILTINS_LOCATION, + FIELD_DECL, NULL_TREE, array_type); + DECL_CHAIN (field) = fields; fields = field; finish_builtin_struct (type, "__gcov_fn_info", fields, NULL_TREE); @@ -647,37 +714,40 @@ build_fn_info_type (unsigned int counters) static tree build_fn_info_value (const struct function_list *function, tree type) { - tree value = NULL_TREE; tree fields = TYPE_FIELDS (type); unsigned ix; - tree array_value = NULL_TREE; + VEC(constructor_elt,gc) *v1 = NULL; + VEC(constructor_elt,gc) *v2 = NULL; /* ident */ - value = tree_cons (fields, build_int_cstu (get_gcov_unsigned_t (), - function->ident), value); - fields = TREE_CHAIN (fields); - - /* checksum */ - value = tree_cons (fields, build_int_cstu (get_gcov_unsigned_t (), - function->checksum), value); - fields = TREE_CHAIN (fields); + CONSTRUCTOR_APPEND_ELT (v1, fields, + build_int_cstu (get_gcov_unsigned_t (), + function->ident)); + fields = DECL_CHAIN (fields); + + /* 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->cfg_checksum)); + fields = DECL_CHAIN (fields); /* counters */ for (ix = 0; ix != GCOV_COUNTERS; ix++) if (prg_ctr_mask & (1 << ix)) - { - tree counters = build_int_cstu (unsigned_type_node, - function->n_ctrs[ix]); - - array_value = tree_cons (NULL_TREE, counters, array_value); - } + CONSTRUCTOR_APPEND_ELT (v2, NULL, + build_int_cstu (get_gcov_unsigned_t (), + function->n_ctrs[ix])); - array_value = build_constructor (TREE_TYPE (fields), nreverse (array_value)); - value = tree_cons (fields, array_value, value); + CONSTRUCTOR_APPEND_ELT (v1, fields, + build_constructor (TREE_TYPE (fields), v2)); - value = build_constructor (type, nreverse (value)); - - return value; + return build_constructor (type, v1); } /* Creates the gcov_ctr_info RECORD_TYPE. */ @@ -691,23 +761,26 @@ build_ctr_info_type (void) tree gcov_merge_fn_type; /* counters */ - field = build_decl (FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ()); - TREE_CHAIN (field) = fields; + field = build_decl (BUILTINS_LOCATION, + FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ()); + DECL_CHAIN (field) = fields; fields = field; /* values */ - field = build_decl (FIELD_DECL, NULL_TREE, gcov_ptr_type); - TREE_CHAIN (field) = fields; + field = build_decl (BUILTINS_LOCATION, + FIELD_DECL, NULL_TREE, gcov_ptr_type); + DECL_CHAIN (field) = fields; fields = field; /* merge */ gcov_merge_fn_type = build_function_type_list (void_type_node, - gcov_ptr_type, unsigned_type_node, + gcov_ptr_type, get_gcov_unsigned_t (), NULL_TREE); - field = build_decl (FIELD_DECL, NULL_TREE, + field = build_decl (BUILTINS_LOCATION, + FIELD_DECL, NULL_TREE, build_pointer_type (gcov_merge_fn_type)); - TREE_CHAIN (field) = fields; + DECL_CHAIN (field) = fields; fields = field; finish_builtin_struct (type, "__gcov_ctr_info", fields, NULL_TREE); @@ -722,22 +795,21 @@ build_ctr_info_type (void) static tree build_ctr_info_value (unsigned int counter, tree type) { - tree value = NULL_TREE; tree fields = TYPE_FIELDS (type); tree fn; + VEC(constructor_elt,gc) *v = NULL; /* counters */ - value = tree_cons (fields, - build_int_cstu (get_gcov_unsigned_t (), - prg_n_ctrs[counter]), - value); - fields = TREE_CHAIN (fields); + CONSTRUCTOR_APPEND_ELT (v, fields, + build_int_cstu (get_gcov_unsigned_t (), + prg_n_ctrs[counter])); + fields = DECL_CHAIN (fields); if (prg_n_ctrs[counter]) { tree array_type; - array_type = build_int_cstu (unsigned_type_node, + array_type = build_int_cstu (get_gcov_unsigned_t (), prg_n_ctrs[counter] - 1); array_type = build_index_type (array_type); array_type = build_array_type (TREE_TYPE (TREE_TYPE (fields)), @@ -746,31 +818,28 @@ build_ctr_info_value (unsigned int counter, tree type) TREE_TYPE (tree_ctr_tables[counter]) = array_type; DECL_SIZE (tree_ctr_tables[counter]) = TYPE_SIZE (array_type); DECL_SIZE_UNIT (tree_ctr_tables[counter]) = TYPE_SIZE_UNIT (array_type); - assemble_variable (tree_ctr_tables[counter], 0, 0, 0); + varpool_finalize_decl (tree_ctr_tables[counter]); - value = tree_cons (fields, - build1 (ADDR_EXPR, TREE_TYPE (fields), - tree_ctr_tables[counter]), - value); + CONSTRUCTOR_APPEND_ELT (v, fields, + build1 (ADDR_EXPR, TREE_TYPE (fields), + tree_ctr_tables[counter])); } else - value = tree_cons (fields, null_pointer_node, value); - fields = TREE_CHAIN (fields); + CONSTRUCTOR_APPEND_ELT (v, fields, null_pointer_node); + fields = DECL_CHAIN (fields); - fn = build_decl (FUNCTION_DECL, + fn = build_decl (BUILTINS_LOCATION, + 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)); + DECL_ASSEMBLER_NAME (fn); /* Initialize assembler name so we can stream out. */ + CONSTRUCTOR_APPEND_ELT (v, fields, build1 (ADDR_EXPR, TREE_TYPE (fields), fn)); - return value; + return build_constructor (type, v); } /* Creates the gcov_info RECORD_TYPE and initializer for it. Returns a @@ -785,13 +854,13 @@ build_gcov_info (void) 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; + int da_file_name_len; unsigned n_fns; const struct function_list *fn; tree string_type; + VEC(constructor_elt,gc) *v1 = NULL; + VEC(constructor_elt,gc) *v2 = NULL; /* Count the number of active counters. */ for (n_ctr_types = 0, ix = 0; ix != GCOV_COUNTERS; ix++) @@ -802,111 +871,107 @@ build_gcov_info (void) const_type = build_qualified_type (type, TYPE_QUAL_CONST); /* Version ident */ - field = build_decl (FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ()); - TREE_CHAIN (field) = fields; + field = build_decl (BUILTINS_LOCATION, + FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ()); + DECL_CHAIN (field) = fields; fields = field; - value = tree_cons (field, build_int_cstu (TREE_TYPE (field), GCOV_VERSION), - value); + CONSTRUCTOR_APPEND_ELT (v1, field, + build_int_cstu (TREE_TYPE (field), GCOV_VERSION)); /* next -- NULL */ - field = build_decl (FIELD_DECL, NULL_TREE, build_pointer_type (const_type)); - TREE_CHAIN (field) = fields; + field = build_decl (BUILTINS_LOCATION, + FIELD_DECL, NULL_TREE, build_pointer_type (const_type)); + DECL_CHAIN (field) = fields; fields = field; - value = tree_cons (field, null_pointer_node, value); + CONSTRUCTOR_APPEND_ELT (v1, field, null_pointer_node); /* stamp */ - field = build_decl (FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ()); - TREE_CHAIN (field) = fields; + field = build_decl (BUILTINS_LOCATION, + FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ()); + DECL_CHAIN (field) = fields; fields = field; - value = tree_cons (field, build_int_cstu (TREE_TYPE (field), local_tick), - value); + CONSTRUCTOR_APPEND_ELT (v1, field, + build_int_cstu (TREE_TYPE (field), local_tick)); /* 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; + field = build_decl (BUILTINS_LOCATION, + FIELD_DECL, NULL_TREE, string_type); + DECL_CHAIN (field) = fields; fields = field; - filename = getpwd (); - filename = (filename && da_file_name[0] != '/' - ? concat (filename, "/", da_file_name, NULL) - : da_file_name); - filename_len = strlen (filename); - filename_string = build_string (filename_len + 1, filename); - if (filename != da_file_name) - free (filename); + da_file_name_len = strlen (da_file_name); + filename_string = build_string (da_file_name_len + 1, da_file_name); TREE_TYPE (filename_string) = build_array_type - (char_type_node, build_index_type - (build_int_cst (NULL_TREE, filename_len))); - value = tree_cons (field, build1 (ADDR_EXPR, string_type, filename_string), - value); + (char_type_node, build_index_type (size_int (da_file_name_len))); + CONSTRUCTOR_APPEND_ELT (v1, field, + build1 (ADDR_EXPR, string_type, filename_string)); /* 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); + CONSTRUCTOR_APPEND_ELT (v2, NULL_TREE, + build_fn_info_value (fn, fn_info_type)); + if (n_fns) { tree array_type; - array_type = build_index_type (build_int_cst (NULL_TREE, n_fns - 1)); + array_type = build_index_type (size_int (n_fns - 1)); array_type = build_array_type (fn_info_type, array_type); - fn_info_value = build_constructor (array_type, nreverse (fn_info_value)); + fn_info_value = build_constructor (array_type, v2); fn_info_value = build1 (ADDR_EXPR, fn_info_ptr_type, fn_info_value); } else fn_info_value = null_pointer_node; /* number of functions */ - field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node); - TREE_CHAIN (field) = fields; + field = build_decl (BUILTINS_LOCATION, + FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ()); + DECL_CHAIN (field) = fields; fields = field; - value = tree_cons (field, - build_int_cstu (unsigned_type_node, n_fns), - value); + CONSTRUCTOR_APPEND_ELT (v1, field, + build_int_cstu (get_gcov_unsigned_t (), n_fns)); /* fn_info table */ - field = build_decl (FIELD_DECL, NULL_TREE, fn_info_ptr_type); - TREE_CHAIN (field) = fields; + field = build_decl (BUILTINS_LOCATION, + FIELD_DECL, NULL_TREE, fn_info_ptr_type); + DECL_CHAIN (field) = fields; fields = field; - value = tree_cons (field, fn_info_value, value); + CONSTRUCTOR_APPEND_ELT (v1, field, fn_info_value); /* counter_mask */ - field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node); - TREE_CHAIN (field) = fields; + field = build_decl (BUILTINS_LOCATION, + FIELD_DECL, NULL_TREE, get_gcov_unsigned_t ()); + DECL_CHAIN (field) = fields; fields = field; - value = tree_cons (field, - build_int_cstu (unsigned_type_node, prg_ctr_mask), - value); + CONSTRUCTOR_APPEND_ELT (v1, field, + build_int_cstu (get_gcov_unsigned_t (), + prg_ctr_mask)); /* counters */ ctr_info_type = build_ctr_info_type (); - ctr_info_ary_type = build_index_type (build_int_cst (NULL_TREE, - n_ctr_types)); + ctr_info_ary_type = build_index_type (size_int (n_ctr_types)); ctr_info_ary_type = build_array_type (ctr_info_type, ctr_info_ary_type); + v2 = NULL; 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; + CONSTRUCTOR_APPEND_ELT (v2, NULL_TREE, + build_ctr_info_value (ix, ctr_info_type)); + ctr_info_value = build_constructor (ctr_info_ary_type, v2); + + field = build_decl (BUILTINS_LOCATION, + FIELD_DECL, NULL_TREE, ctr_info_ary_type); + DECL_CHAIN (field) = fields; fields = field; - value = tree_cons (field, ctr_info_value, value); + CONSTRUCTOR_APPEND_ELT (v1, field, ctr_info_value); finish_builtin_struct (type, "__gcov_info", fields, NULL_TREE); - value = build_constructor (type, nreverse (value)); - - return value; + return build_constructor (type, v1); } /* Write out the structure which libgcov uses to locate all the @@ -926,28 +991,30 @@ create_coverage (void) t = build_gcov_info (); - gcov_info = build_decl (VAR_DECL, NULL_TREE, TREE_TYPE (t)); + gcov_info = build_decl (BUILTINS_LOCATION, + VAR_DECL, NULL_TREE, TREE_TYPE (t)); TREE_STATIC (gcov_info) = 1; ASM_GENERATE_INTERNAL_LABEL (name_buf, "LPBX", 0); DECL_NAME (gcov_info) = get_identifier (name_buf); DECL_INITIAL (gcov_info) = t; /* Build structure. */ - assemble_variable (gcov_info, 0, 0, 0); + varpool_finalize_decl (gcov_info); /* Build a decl for __gcov_init. */ t = build_pointer_type (TREE_TYPE (gcov_info)); t = build_function_type_list (void_type_node, t, NULL); - t = build_decl (FUNCTION_DECL, get_identifier ("__gcov_init"), t); + t = build_decl (BUILTINS_LOCATION, + FUNCTION_DECL, get_identifier ("__gcov_init"), t); TREE_PUBLIC (t) = 1; DECL_EXTERNAL (t) = 1; + DECL_ASSEMBLER_NAME (t); /* Initialize assembler name so we can stream out. */ gcov_init = t; /* Generate a call to __gcov_init(&gcov_info). */ body = NULL; t = build_fold_addr_expr (gcov_info); - t = tree_cons (NULL, t, NULL); - t = build_function_call_expr (gcov_init, t); + t = build_call_expr (gcov_init, 1, t); append_to_statement_list (t, &body); /* Generate a constructor to run it. */ @@ -961,18 +1028,36 @@ void coverage_init (const char *filename) { int len = strlen (filename); + /* + 1 for extra '/', in case prefix doesn't end with /. */ + int prefix_len; + + if (profile_data_prefix == 0 && !IS_ABSOLUTE_PATH(&filename[0])) + profile_data_prefix = getpwd (); + + prefix_len = (profile_data_prefix) ? strlen (profile_data_prefix) + 1 : 0; /* Name of da file. */ - da_file_name = xmalloc (len + strlen (GCOV_DATA_SUFFIX) + 1); - strcpy (da_file_name, filename); + da_file_name = XNEWVEC (char, len + strlen (GCOV_DATA_SUFFIX) + + prefix_len + 1); + + if (profile_data_prefix) + { + strcpy (da_file_name, profile_data_prefix); + da_file_name[prefix_len - 1] = '/'; + da_file_name[prefix_len] = 0; + } + else + da_file_name[0] = 0; + strcat (da_file_name, filename); strcat (da_file_name, GCOV_DATA_SUFFIX); /* Name of bbg file. */ - bbg_file_name = xmalloc (len + strlen (GCOV_NOTE_SUFFIX) + 1); + bbg_file_name = XNEWVEC (char, len + strlen (GCOV_NOTE_SUFFIX) + 1); strcpy (bbg_file_name, filename); strcat (bbg_file_name, GCOV_NOTE_SUFFIX); - read_counts_file (); + if (flag_branch_probabilities) + read_counts_file (); } /* Performs file-level cleanup. Close graph file, generate coverage