xref: /dflybsd-src/contrib/gcc-8.0/gcc/coverage.c (revision 95059079af47f9a66a175f374f2da1a5020e3255)
138fd1498Szrj /* Read and write coverage files, and associated functionality.
238fd1498Szrj    Copyright (C) 1990-2018 Free Software Foundation, Inc.
338fd1498Szrj    Contributed by James E. Wilson, UC Berkeley/Cygnus Support;
438fd1498Szrj    based on some ideas from Dain Samples of UC Berkeley.
538fd1498Szrj    Further mangling by Bob Manson, Cygnus Support.
638fd1498Szrj    Further mangled by Nathan Sidwell, CodeSourcery
738fd1498Szrj 
838fd1498Szrj This file is part of GCC.
938fd1498Szrj 
1038fd1498Szrj GCC is free software; you can redistribute it and/or modify it under
1138fd1498Szrj the terms of the GNU General Public License as published by the Free
1238fd1498Szrj Software Foundation; either version 3, or (at your option) any later
1338fd1498Szrj version.
1438fd1498Szrj 
1538fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT ANY
1638fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or
1738fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1838fd1498Szrj for more details.
1938fd1498Szrj 
2038fd1498Szrj You should have received a copy of the GNU General Public License
2138fd1498Szrj along with GCC; see the file COPYING3.  If not see
2238fd1498Szrj <http://www.gnu.org/licenses/>.  */
2338fd1498Szrj 
2438fd1498Szrj 
2538fd1498Szrj #define GCOV_LINKAGE
2638fd1498Szrj 
2738fd1498Szrj #include "config.h"
2838fd1498Szrj #include "system.h"
2938fd1498Szrj #include "coretypes.h"
3038fd1498Szrj #include "backend.h"
3138fd1498Szrj #include "target.h"
3238fd1498Szrj #include "rtl.h"
3338fd1498Szrj #include "tree.h"
3438fd1498Szrj #include "tree-pass.h"
3538fd1498Szrj #include "memmodel.h"
3638fd1498Szrj #include "tm_p.h"
3738fd1498Szrj #include "stringpool.h"
3838fd1498Szrj #include "cgraph.h"
3938fd1498Szrj #include "coverage.h"
4038fd1498Szrj #include "diagnostic-core.h"
4138fd1498Szrj #include "fold-const.h"
4238fd1498Szrj #include "stor-layout.h"
4338fd1498Szrj #include "output.h"
4438fd1498Szrj #include "toplev.h"
4538fd1498Szrj #include "langhooks.h"
4638fd1498Szrj #include "tree-iterator.h"
4738fd1498Szrj #include "context.h"
4838fd1498Szrj #include "pass_manager.h"
4938fd1498Szrj #include "intl.h"
5038fd1498Szrj #include "params.h"
5138fd1498Szrj #include "auto-profile.h"
5238fd1498Szrj 
5338fd1498Szrj #include "gcov-io.c"
5438fd1498Szrj 
5538fd1498Szrj struct GTY((chain_next ("%h.next"))) coverage_data
5638fd1498Szrj {
5738fd1498Szrj   struct coverage_data *next;	 /* next function */
5838fd1498Szrj   unsigned ident;		 /* function ident */
5938fd1498Szrj   unsigned lineno_checksum;	 /* function lineno checksum */
6038fd1498Szrj   unsigned cfg_checksum;	 /* function cfg checksum */
6138fd1498Szrj   tree fn_decl;			 /* the function decl */
6238fd1498Szrj   tree ctr_vars[GCOV_COUNTERS];	 /* counter variables.  */
6338fd1498Szrj };
6438fd1498Szrj 
6538fd1498Szrj /* Counts information for a function.  */
6638fd1498Szrj struct counts_entry : pointer_hash <counts_entry>
6738fd1498Szrj {
6838fd1498Szrj   /* We hash by  */
6938fd1498Szrj   unsigned ident;
7038fd1498Szrj   unsigned ctr;
7138fd1498Szrj 
7238fd1498Szrj   /* Store  */
7338fd1498Szrj   unsigned lineno_checksum;
7438fd1498Szrj   unsigned cfg_checksum;
7538fd1498Szrj   gcov_type *counts;
7638fd1498Szrj   struct gcov_ctr_summary summary;
7738fd1498Szrj 
7838fd1498Szrj   /* hash_table support.  */
7938fd1498Szrj   static inline hashval_t hash (const counts_entry *);
8038fd1498Szrj   static int equal (const counts_entry *, const counts_entry *);
8138fd1498Szrj   static void remove (counts_entry *);
8238fd1498Szrj };
8338fd1498Szrj 
8438fd1498Szrj static GTY(()) struct coverage_data *functions_head = 0;
8538fd1498Szrj static struct coverage_data **functions_tail = &functions_head;
8638fd1498Szrj static unsigned no_coverage = 0;
8738fd1498Szrj 
8838fd1498Szrj /* Cumulative counter information for whole program.  */
8938fd1498Szrj static unsigned prg_ctr_mask; /* Mask of counter types generated.  */
9038fd1498Szrj 
9138fd1498Szrj /* Counter information for current function.  */
9238fd1498Szrj static unsigned fn_ctr_mask; /* Mask of counters used.  */
9338fd1498Szrj static GTY(()) tree fn_v_ctrs[GCOV_COUNTERS];   /* counter variables.  */
9438fd1498Szrj static unsigned fn_n_ctrs[GCOV_COUNTERS]; /* Counters allocated.  */
9538fd1498Szrj static unsigned fn_b_ctrs[GCOV_COUNTERS]; /* Allocation base.  */
9638fd1498Szrj 
9738fd1498Szrj /* Coverage info VAR_DECL and function info type nodes.  */
9838fd1498Szrj static GTY(()) tree gcov_info_var;
9938fd1498Szrj static GTY(()) tree gcov_fn_info_type;
10038fd1498Szrj static GTY(()) tree gcov_fn_info_ptr_type;
10138fd1498Szrj 
10238fd1498Szrj /* Name of the notes (gcno) output file.  The "bbg" prefix is for
10338fd1498Szrj    historical reasons, when the notes file contained only the
10438fd1498Szrj    basic block graph notes.
10538fd1498Szrj    If this is NULL we're not writing to the notes file.  */
10638fd1498Szrj static char *bbg_file_name;
10738fd1498Szrj 
10838fd1498Szrj /* File stamp for notes file.  */
10938fd1498Szrj static unsigned bbg_file_stamp;
11038fd1498Szrj 
11138fd1498Szrj /* Name of the count data (gcda) file.  */
11238fd1498Szrj static char *da_file_name;
11338fd1498Szrj 
11438fd1498Szrj /* The names of merge functions for counters.  */
11538fd1498Szrj #define STR(str) #str
11638fd1498Szrj #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) STR(__gcov_merge ## FN_TYPE),
11738fd1498Szrj static const char *const ctr_merge_functions[GCOV_COUNTERS] = {
11838fd1498Szrj #include "gcov-counter.def"
11938fd1498Szrj };
12038fd1498Szrj #undef DEF_GCOV_COUNTER
12138fd1498Szrj #undef STR
12238fd1498Szrj 
12338fd1498Szrj #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) NAME,
12438fd1498Szrj static const char *const ctr_names[GCOV_COUNTERS] = {
12538fd1498Szrj #include "gcov-counter.def"
12638fd1498Szrj };
12738fd1498Szrj #undef DEF_GCOV_COUNTER
12838fd1498Szrj 
12938fd1498Szrj /* Forward declarations.  */
13038fd1498Szrj static void read_counts_file (void);
13138fd1498Szrj static tree build_var (tree, tree, int);
13238fd1498Szrj static void build_fn_info_type (tree, unsigned, tree);
13338fd1498Szrj static void build_info_type (tree, tree);
13438fd1498Szrj static tree build_fn_info (const struct coverage_data *, tree, tree);
13538fd1498Szrj static tree build_info (tree, tree);
13638fd1498Szrj static bool coverage_obj_init (void);
13738fd1498Szrj static vec<constructor_elt, va_gc> *coverage_obj_fn
13838fd1498Szrj (vec<constructor_elt, va_gc> *, tree, struct coverage_data const *);
13938fd1498Szrj static void coverage_obj_finish (vec<constructor_elt, va_gc> *);
14038fd1498Szrj 
14138fd1498Szrj /* Return the type node for gcov_type.  */
14238fd1498Szrj 
14338fd1498Szrj tree
get_gcov_type(void)14438fd1498Szrj get_gcov_type (void)
14538fd1498Szrj {
14638fd1498Szrj   scalar_int_mode mode
14738fd1498Szrj     = smallest_int_mode_for_size (LONG_LONG_TYPE_SIZE > 32 ? 64 : 32);
14838fd1498Szrj   return lang_hooks.types.type_for_mode (mode, false);
14938fd1498Szrj }
15038fd1498Szrj 
15138fd1498Szrj /* Return the type node for gcov_unsigned_t.  */
15238fd1498Szrj 
15338fd1498Szrj static tree
get_gcov_unsigned_t(void)15438fd1498Szrj get_gcov_unsigned_t (void)
15538fd1498Szrj {
15638fd1498Szrj   scalar_int_mode mode = smallest_int_mode_for_size (32);
15738fd1498Szrj   return lang_hooks.types.type_for_mode (mode, true);
15838fd1498Szrj }
15938fd1498Szrj 
16038fd1498Szrj inline hashval_t
hash(const counts_entry * entry)16138fd1498Szrj counts_entry::hash (const counts_entry *entry)
16238fd1498Szrj {
16338fd1498Szrj   return entry->ident * GCOV_COUNTERS + entry->ctr;
16438fd1498Szrj }
16538fd1498Szrj 
16638fd1498Szrj inline int
equal(const counts_entry * entry1,const counts_entry * entry2)16738fd1498Szrj counts_entry::equal (const counts_entry *entry1, const counts_entry *entry2)
16838fd1498Szrj {
16938fd1498Szrj   return entry1->ident == entry2->ident && entry1->ctr == entry2->ctr;
17038fd1498Szrj }
17138fd1498Szrj 
17238fd1498Szrj inline void
remove(counts_entry * entry)17338fd1498Szrj counts_entry::remove (counts_entry *entry)
17438fd1498Szrj {
17538fd1498Szrj   free (entry->counts);
17638fd1498Szrj   free (entry);
17738fd1498Szrj }
17838fd1498Szrj 
17938fd1498Szrj /* Hash table of count data.  */
18038fd1498Szrj static hash_table<counts_entry> *counts_hash;
18138fd1498Szrj 
18238fd1498Szrj /* Read in the counts file, if available.  */
18338fd1498Szrj 
18438fd1498Szrj static void
read_counts_file(void)18538fd1498Szrj read_counts_file (void)
18638fd1498Szrj {
18738fd1498Szrj   gcov_unsigned_t fn_ident = 0;
18838fd1498Szrj   struct gcov_summary summary;
18938fd1498Szrj   unsigned new_summary = 1;
19038fd1498Szrj   gcov_unsigned_t tag;
19138fd1498Szrj   int is_error = 0;
19238fd1498Szrj   unsigned lineno_checksum = 0;
19338fd1498Szrj   unsigned cfg_checksum = 0;
19438fd1498Szrj 
19538fd1498Szrj   if (!gcov_open (da_file_name, 1))
19638fd1498Szrj     return;
19738fd1498Szrj 
19838fd1498Szrj   if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
19938fd1498Szrj     {
20038fd1498Szrj       warning (0, "%qs is not a gcov data file", da_file_name);
20138fd1498Szrj       gcov_close ();
20238fd1498Szrj       return;
20338fd1498Szrj     }
20438fd1498Szrj   else if ((tag = gcov_read_unsigned ()) != GCOV_VERSION)
20538fd1498Szrj     {
20638fd1498Szrj       char v[4], e[4];
20738fd1498Szrj 
20838fd1498Szrj       GCOV_UNSIGNED2STRING (v, tag);
20938fd1498Szrj       GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
21038fd1498Szrj 
21138fd1498Szrj       warning (0, "%qs is version %q.*s, expected version %q.*s",
21238fd1498Szrj  	       da_file_name, 4, v, 4, e);
21338fd1498Szrj       gcov_close ();
21438fd1498Szrj       return;
21538fd1498Szrj     }
21638fd1498Szrj 
21738fd1498Szrj   /* Read the stamp, used for creating a generation count.  */
21838fd1498Szrj   tag = gcov_read_unsigned ();
21938fd1498Szrj   bbg_file_stamp = crc32_unsigned (bbg_file_stamp, tag);
22038fd1498Szrj 
22138fd1498Szrj   counts_hash = new hash_table<counts_entry> (10);
22238fd1498Szrj   while ((tag = gcov_read_unsigned ()))
22338fd1498Szrj     {
22438fd1498Szrj       gcov_unsigned_t length;
22538fd1498Szrj       gcov_position_t offset;
22638fd1498Szrj 
22738fd1498Szrj       length = gcov_read_unsigned ();
22838fd1498Szrj       offset = gcov_position ();
22938fd1498Szrj       if (tag == GCOV_TAG_FUNCTION)
23038fd1498Szrj 	{
23138fd1498Szrj 	  if (length)
23238fd1498Szrj 	    {
23338fd1498Szrj 	      fn_ident = gcov_read_unsigned ();
23438fd1498Szrj 	      lineno_checksum = gcov_read_unsigned ();
23538fd1498Szrj 	      cfg_checksum = gcov_read_unsigned ();
23638fd1498Szrj 	    }
23738fd1498Szrj 	  else
23838fd1498Szrj 	    fn_ident = lineno_checksum = cfg_checksum = 0;
23938fd1498Szrj 	  new_summary = 1;
24038fd1498Szrj 	}
24138fd1498Szrj       else if (tag == GCOV_TAG_PROGRAM_SUMMARY)
24238fd1498Szrj 	{
24338fd1498Szrj 	  struct gcov_summary sum;
24438fd1498Szrj 	  unsigned ix;
24538fd1498Szrj 
24638fd1498Szrj 	  if (new_summary)
24738fd1498Szrj 	    memset (&summary, 0, sizeof (summary));
24838fd1498Szrj 
24938fd1498Szrj 	  gcov_read_summary (&sum);
25038fd1498Szrj 	  for (ix = 0; ix != GCOV_COUNTERS_SUMMABLE; ix++)
25138fd1498Szrj 	    {
25238fd1498Szrj 	      summary.ctrs[ix].runs += sum.ctrs[ix].runs;
25338fd1498Szrj 	      summary.ctrs[ix].sum_all += sum.ctrs[ix].sum_all;
25438fd1498Szrj 	      if (summary.ctrs[ix].run_max < sum.ctrs[ix].run_max)
25538fd1498Szrj 		summary.ctrs[ix].run_max = sum.ctrs[ix].run_max;
25638fd1498Szrj 	      summary.ctrs[ix].sum_max += sum.ctrs[ix].sum_max;
25738fd1498Szrj 	    }
25838fd1498Szrj           if (new_summary)
25938fd1498Szrj             memcpy (summary.ctrs[GCOV_COUNTER_ARCS].histogram,
26038fd1498Szrj                     sum.ctrs[GCOV_COUNTER_ARCS].histogram,
26138fd1498Szrj                     sizeof (gcov_bucket_type) * GCOV_HISTOGRAM_SIZE);
26238fd1498Szrj           else
26338fd1498Szrj             gcov_histogram_merge (summary.ctrs[GCOV_COUNTER_ARCS].histogram,
26438fd1498Szrj                                   sum.ctrs[GCOV_COUNTER_ARCS].histogram);
26538fd1498Szrj 	  new_summary = 0;
26638fd1498Szrj 	}
26738fd1498Szrj       else if (GCOV_TAG_IS_COUNTER (tag) && fn_ident)
26838fd1498Szrj 	{
26938fd1498Szrj 	  counts_entry **slot, *entry, elt;
27038fd1498Szrj 	  unsigned n_counts = GCOV_TAG_COUNTER_NUM (length);
27138fd1498Szrj 	  unsigned ix;
27238fd1498Szrj 
27338fd1498Szrj 	  elt.ident = fn_ident;
27438fd1498Szrj 	  elt.ctr = GCOV_COUNTER_FOR_TAG (tag);
27538fd1498Szrj 
27638fd1498Szrj 	  slot = counts_hash->find_slot (&elt, INSERT);
27738fd1498Szrj 	  entry = *slot;
27838fd1498Szrj 	  if (!entry)
27938fd1498Szrj 	    {
28038fd1498Szrj 	      *slot = entry = XCNEW (counts_entry);
28138fd1498Szrj 	      entry->ident = fn_ident;
28238fd1498Szrj 	      entry->ctr = elt.ctr;
28338fd1498Szrj 	      entry->lineno_checksum = lineno_checksum;
28438fd1498Szrj 	      entry->cfg_checksum = cfg_checksum;
28538fd1498Szrj               if (elt.ctr < GCOV_COUNTERS_SUMMABLE)
28638fd1498Szrj                 entry->summary = summary.ctrs[elt.ctr];
28738fd1498Szrj               entry->summary.num = n_counts;
28838fd1498Szrj 	      entry->counts = XCNEWVEC (gcov_type, n_counts);
28938fd1498Szrj 	    }
29038fd1498Szrj 	  else if (entry->lineno_checksum != lineno_checksum
29138fd1498Szrj 		   || entry->cfg_checksum != cfg_checksum)
29238fd1498Szrj 	    {
29338fd1498Szrj 	      error ("Profile data for function %u is corrupted", fn_ident);
29438fd1498Szrj 	      error ("checksum is (%x,%x) instead of (%x,%x)",
29538fd1498Szrj 		     entry->lineno_checksum, entry->cfg_checksum,
29638fd1498Szrj 		     lineno_checksum, cfg_checksum);
29738fd1498Szrj 	      delete counts_hash;
29838fd1498Szrj 	      counts_hash = NULL;
29938fd1498Szrj 	      break;
30038fd1498Szrj 	    }
30138fd1498Szrj 	  else if (entry->summary.num != n_counts)
30238fd1498Szrj 	    {
30338fd1498Szrj 	      error ("Profile data for function %u is corrupted", fn_ident);
30438fd1498Szrj 	      error ("number of counters is %d instead of %d", entry->summary.num, n_counts);
30538fd1498Szrj 	      delete counts_hash;
30638fd1498Szrj 	      counts_hash = NULL;
30738fd1498Szrj 	      break;
30838fd1498Szrj 	    }
30938fd1498Szrj 	  else if (elt.ctr >= GCOV_COUNTERS_SUMMABLE)
31038fd1498Szrj 	    {
31138fd1498Szrj 	      error ("cannot merge separate %s counters for function %u",
31238fd1498Szrj 		     ctr_names[elt.ctr], fn_ident);
31338fd1498Szrj 	      goto skip_merge;
31438fd1498Szrj 	    }
31538fd1498Szrj 	  else
31638fd1498Szrj 	    {
31738fd1498Szrj 	      entry->summary.runs += summary.ctrs[elt.ctr].runs;
31838fd1498Szrj 	      entry->summary.sum_all += summary.ctrs[elt.ctr].sum_all;
31938fd1498Szrj 	      if (entry->summary.run_max < summary.ctrs[elt.ctr].run_max)
32038fd1498Szrj 		entry->summary.run_max = summary.ctrs[elt.ctr].run_max;
32138fd1498Szrj 	      entry->summary.sum_max += summary.ctrs[elt.ctr].sum_max;
32238fd1498Szrj 	    }
32338fd1498Szrj 	  for (ix = 0; ix != n_counts; ix++)
32438fd1498Szrj 	    entry->counts[ix] += gcov_read_counter ();
32538fd1498Szrj 	skip_merge:;
32638fd1498Szrj 	}
32738fd1498Szrj       gcov_sync (offset, length);
32838fd1498Szrj       if ((is_error = gcov_is_error ()))
32938fd1498Szrj 	{
33038fd1498Szrj 	  error (is_error < 0
33138fd1498Szrj 		 ? G_("%qs has overflowed")
33238fd1498Szrj 		 : G_("%qs is corrupted"),
33338fd1498Szrj 		 da_file_name);
33438fd1498Szrj 	  delete counts_hash;
33538fd1498Szrj 	  counts_hash = NULL;
33638fd1498Szrj 	  break;
33738fd1498Szrj 	}
33838fd1498Szrj     }
33938fd1498Szrj 
34038fd1498Szrj   gcov_close ();
34138fd1498Szrj }
34238fd1498Szrj 
34338fd1498Szrj /* Returns the counters for a particular tag.  */
34438fd1498Szrj 
34538fd1498Szrj gcov_type *
get_coverage_counts(unsigned counter,unsigned expected,unsigned cfg_checksum,unsigned lineno_checksum,const struct gcov_ctr_summary ** summary)34638fd1498Szrj get_coverage_counts (unsigned counter, unsigned expected,
34738fd1498Szrj                      unsigned cfg_checksum, unsigned lineno_checksum,
34838fd1498Szrj 		     const struct gcov_ctr_summary **summary)
34938fd1498Szrj {
35038fd1498Szrj   counts_entry *entry, elt;
35138fd1498Szrj 
35238fd1498Szrj   /* No hash table, no counts.  */
35338fd1498Szrj   if (!counts_hash)
35438fd1498Szrj     {
35538fd1498Szrj       static int warned = 0;
35638fd1498Szrj 
35738fd1498Szrj       if (!warned++ && dump_enabled_p ())
35838fd1498Szrj 	dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, input_location,
35938fd1498Szrj                          (flag_guess_branch_prob
36038fd1498Szrj                           ? "file %s not found, execution counts estimated\n"
36138fd1498Szrj                           : "file %s not found, execution counts assumed to "
36238fd1498Szrj                             "be zero\n"),
36338fd1498Szrj                          da_file_name);
36438fd1498Szrj       return NULL;
36538fd1498Szrj     }
36638fd1498Szrj   if (PARAM_VALUE (PARAM_PROFILE_FUNC_INTERNAL_ID))
36738fd1498Szrj     elt.ident = current_function_funcdef_no + 1;
36838fd1498Szrj   else
36938fd1498Szrj     {
37038fd1498Szrj       gcc_assert (coverage_node_map_initialized_p ());
371*58e805e6Szrj       elt.ident = cgraph_node::get (current_function_decl)->profile_id;
37238fd1498Szrj     }
37338fd1498Szrj   elt.ctr = counter;
37438fd1498Szrj   entry = counts_hash->find (&elt);
37538fd1498Szrj   if (!entry || !entry->summary.num)
37638fd1498Szrj     /* The function was not emitted, or is weak and not chosen in the
37738fd1498Szrj        final executable.  Silently fail, because there's nothing we
37838fd1498Szrj        can do about it.  */
37938fd1498Szrj     return NULL;
38038fd1498Szrj 
38138fd1498Szrj   if (entry->cfg_checksum != cfg_checksum
38238fd1498Szrj       || entry->summary.num != expected)
38338fd1498Szrj     {
38438fd1498Szrj       static int warned = 0;
38538fd1498Szrj       bool warning_printed = false;
38638fd1498Szrj       tree id = DECL_ASSEMBLER_NAME (current_function_decl);
38738fd1498Szrj 
38838fd1498Szrj       warning_printed =
38938fd1498Szrj 	warning_at (input_location, OPT_Wcoverage_mismatch,
39038fd1498Szrj 		    "the control flow of function %qE does not match "
39138fd1498Szrj 		    "its profile data (counter %qs)", id, ctr_names[counter]);
39238fd1498Szrj       if (warning_printed && dump_enabled_p ())
39338fd1498Szrj 	{
39438fd1498Szrj           dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, input_location,
39538fd1498Szrj                            "use -Wno-error=coverage-mismatch to tolerate "
39638fd1498Szrj                            "the mismatch but performance may drop if the "
39738fd1498Szrj                            "function is hot\n");
39838fd1498Szrj 
39938fd1498Szrj 	  if (!seen_error ()
40038fd1498Szrj 	      && !warned++)
40138fd1498Szrj 	    {
40238fd1498Szrj 	      dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, input_location,
40338fd1498Szrj                                "coverage mismatch ignored\n");
40438fd1498Szrj 	      dump_printf (MSG_OPTIMIZED_LOCATIONS,
40538fd1498Szrj                            flag_guess_branch_prob
40638fd1498Szrj                            ? G_("execution counts estimated\n")
40738fd1498Szrj                            : G_("execution counts assumed to be zero\n"));
40838fd1498Szrj 	      if (!flag_guess_branch_prob)
40938fd1498Szrj 		dump_printf (MSG_OPTIMIZED_LOCATIONS,
41038fd1498Szrj                              "this can result in poorly optimized code\n");
41138fd1498Szrj 	    }
41238fd1498Szrj 	}
41338fd1498Szrj 
41438fd1498Szrj       return NULL;
41538fd1498Szrj     }
41638fd1498Szrj   else if (entry->lineno_checksum != lineno_checksum)
41738fd1498Szrj     {
41838fd1498Szrj       warning (OPT_Wcoverage_mismatch,
41938fd1498Szrj                "source locations for function %qE have changed,"
42038fd1498Szrj 	       " the profile data may be out of date",
42138fd1498Szrj 	       DECL_ASSEMBLER_NAME (current_function_decl));
42238fd1498Szrj     }
42338fd1498Szrj 
42438fd1498Szrj   if (summary)
42538fd1498Szrj     *summary = &entry->summary;
42638fd1498Szrj 
42738fd1498Szrj   return entry->counts;
42838fd1498Szrj }
42938fd1498Szrj 
43038fd1498Szrj /* Allocate NUM counters of type COUNTER. Returns nonzero if the
43138fd1498Szrj    allocation succeeded.  */
43238fd1498Szrj 
43338fd1498Szrj int
coverage_counter_alloc(unsigned counter,unsigned num)43438fd1498Szrj coverage_counter_alloc (unsigned counter, unsigned num)
43538fd1498Szrj {
43638fd1498Szrj   if (no_coverage)
43738fd1498Szrj     return 0;
43838fd1498Szrj 
43938fd1498Szrj   if (!num)
44038fd1498Szrj     return 1;
44138fd1498Szrj 
44238fd1498Szrj   if (!fn_v_ctrs[counter])
44338fd1498Szrj     {
44438fd1498Szrj       tree array_type = build_array_type (get_gcov_type (), NULL_TREE);
44538fd1498Szrj 
44638fd1498Szrj       fn_v_ctrs[counter]
44738fd1498Szrj 	= build_var (current_function_decl, array_type, counter);
44838fd1498Szrj     }
44938fd1498Szrj 
45038fd1498Szrj   fn_b_ctrs[counter] = fn_n_ctrs[counter];
45138fd1498Szrj   fn_n_ctrs[counter] += num;
45238fd1498Szrj 
45338fd1498Szrj   fn_ctr_mask |= 1 << counter;
45438fd1498Szrj   return 1;
45538fd1498Szrj }
45638fd1498Szrj 
45738fd1498Szrj /* Generate a tree to access COUNTER NO.  */
45838fd1498Szrj 
45938fd1498Szrj tree
tree_coverage_counter_ref(unsigned counter,unsigned no)46038fd1498Szrj tree_coverage_counter_ref (unsigned counter, unsigned no)
46138fd1498Szrj {
46238fd1498Szrj   tree gcov_type_node = get_gcov_type ();
46338fd1498Szrj 
46438fd1498Szrj   gcc_assert (no < fn_n_ctrs[counter] - fn_b_ctrs[counter]);
46538fd1498Szrj 
46638fd1498Szrj   no += fn_b_ctrs[counter];
46738fd1498Szrj 
46838fd1498Szrj   /* "no" here is an array index, scaled to bytes later.  */
46938fd1498Szrj   return build4 (ARRAY_REF, gcov_type_node, fn_v_ctrs[counter],
47038fd1498Szrj 		 build_int_cst (integer_type_node, no), NULL, NULL);
47138fd1498Szrj }
47238fd1498Szrj 
47338fd1498Szrj /* Generate a tree to access the address of COUNTER NO.  */
47438fd1498Szrj 
47538fd1498Szrj tree
tree_coverage_counter_addr(unsigned counter,unsigned no)47638fd1498Szrj tree_coverage_counter_addr (unsigned counter, unsigned no)
47738fd1498Szrj {
47838fd1498Szrj   tree gcov_type_node = get_gcov_type ();
47938fd1498Szrj 
48038fd1498Szrj   gcc_assert (no < fn_n_ctrs[counter] - fn_b_ctrs[counter]);
48138fd1498Szrj   no += fn_b_ctrs[counter];
48238fd1498Szrj 
48338fd1498Szrj   /* "no" here is an array index, scaled to bytes later.  */
48438fd1498Szrj   return build_fold_addr_expr (build4 (ARRAY_REF, gcov_type_node,
48538fd1498Szrj 				       fn_v_ctrs[counter],
48638fd1498Szrj 				       build_int_cst (integer_type_node, no),
48738fd1498Szrj 				       NULL, NULL));
48838fd1498Szrj }
48938fd1498Szrj 
49038fd1498Szrj 
49138fd1498Szrj /* Generate a checksum for a string.  CHKSUM is the current
49238fd1498Szrj    checksum.  */
49338fd1498Szrj 
49438fd1498Szrj static unsigned
coverage_checksum_string(unsigned chksum,const char * string)49538fd1498Szrj coverage_checksum_string (unsigned chksum, const char *string)
49638fd1498Szrj {
49738fd1498Szrj   int i;
49838fd1498Szrj   char *dup = NULL;
49938fd1498Szrj 
50038fd1498Szrj   /* Look for everything that looks if it were produced by
50138fd1498Szrj      get_file_function_name and zero out the second part
50238fd1498Szrj      that may result from flag_random_seed.  This is not critical
50338fd1498Szrj      as the checksums are used only for sanity checking.  */
50438fd1498Szrj   for (i = 0; string[i]; i++)
50538fd1498Szrj     {
50638fd1498Szrj       int offset = 0;
50738fd1498Szrj       if (!strncmp (string + i, "_GLOBAL__N_", 11))
50838fd1498Szrj       offset = 11;
50938fd1498Szrj       if (!strncmp (string + i, "_GLOBAL__", 9))
51038fd1498Szrj       offset = 9;
51138fd1498Szrj 
51238fd1498Szrj       /* C++ namespaces do have scheme:
51338fd1498Szrj          _GLOBAL__N_<filename>_<wrongmagicnumber>_<magicnumber>functionname
51438fd1498Szrj        since filename might contain extra underscores there seems
51538fd1498Szrj        to be no better chance then walk all possible offsets looking
51638fd1498Szrj        for magicnumber.  */
51738fd1498Szrj       if (offset)
51838fd1498Szrj 	{
51938fd1498Szrj 	  for (i = i + offset; string[i]; i++)
52038fd1498Szrj 	    if (string[i]=='_')
52138fd1498Szrj 	      {
52238fd1498Szrj 		int y;
52338fd1498Szrj 
52438fd1498Szrj 		for (y = 1; y < 9; y++)
52538fd1498Szrj 		  if (!(string[i + y] >= '0' && string[i + y] <= '9')
52638fd1498Szrj 		      && !(string[i + y] >= 'A' && string[i + y] <= 'F'))
52738fd1498Szrj 		    break;
52838fd1498Szrj 		if (y != 9 || string[i + 9] != '_')
52938fd1498Szrj 		  continue;
53038fd1498Szrj 		for (y = 10; y < 18; y++)
53138fd1498Szrj 		  if (!(string[i + y] >= '0' && string[i + y] <= '9')
53238fd1498Szrj 		      && !(string[i + y] >= 'A' && string[i + y] <= 'F'))
53338fd1498Szrj 		    break;
53438fd1498Szrj 		if (y != 18)
53538fd1498Szrj 		  continue;
53638fd1498Szrj 		if (!dup)
53738fd1498Szrj 		  string = dup = xstrdup (string);
53838fd1498Szrj 		for (y = 10; y < 18; y++)
53938fd1498Szrj 		  dup[i + y] = '0';
54038fd1498Szrj 	      }
54138fd1498Szrj 	  break;
54238fd1498Szrj 	}
54338fd1498Szrj     }
54438fd1498Szrj 
54538fd1498Szrj   chksum = crc32_string (chksum, string);
54638fd1498Szrj   free (dup);
54738fd1498Szrj 
54838fd1498Szrj   return chksum;
54938fd1498Szrj }
55038fd1498Szrj 
55138fd1498Szrj /* Compute checksum for the current function.  We generate a CRC32.  */
55238fd1498Szrj 
55338fd1498Szrj unsigned
coverage_compute_lineno_checksum(void)55438fd1498Szrj coverage_compute_lineno_checksum (void)
55538fd1498Szrj {
55638fd1498Szrj   expanded_location xloc
55738fd1498Szrj     = expand_location (DECL_SOURCE_LOCATION (current_function_decl));
55838fd1498Szrj   unsigned chksum = xloc.line;
55938fd1498Szrj 
56038fd1498Szrj   if (xloc.file)
56138fd1498Szrj     chksum = coverage_checksum_string (chksum, xloc.file);
56238fd1498Szrj   chksum = coverage_checksum_string
56338fd1498Szrj     (chksum, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl)));
56438fd1498Szrj 
56538fd1498Szrj   return chksum;
56638fd1498Szrj }
56738fd1498Szrj 
56838fd1498Szrj /* Compute profile ID.  This is better to be unique in whole program.  */
56938fd1498Szrj 
57038fd1498Szrj unsigned
coverage_compute_profile_id(struct cgraph_node * n)57138fd1498Szrj coverage_compute_profile_id (struct cgraph_node *n)
57238fd1498Szrj {
57338fd1498Szrj   unsigned chksum;
57438fd1498Szrj 
57538fd1498Szrj   /* Externally visible symbols have unique name.  */
57638fd1498Szrj   if (TREE_PUBLIC (n->decl) || DECL_EXTERNAL (n->decl) || n->unique_name)
57738fd1498Szrj     {
57838fd1498Szrj       chksum = coverage_checksum_string
57938fd1498Szrj 	(0, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (n->decl)));
58038fd1498Szrj     }
58138fd1498Szrj   else
58238fd1498Szrj     {
58338fd1498Szrj       expanded_location xloc
58438fd1498Szrj 	= expand_location (DECL_SOURCE_LOCATION (n->decl));
58538fd1498Szrj       bool use_name_only = (PARAM_VALUE (PARAM_PROFILE_FUNC_INTERNAL_ID) == 0);
58638fd1498Szrj 
58738fd1498Szrj       chksum = (use_name_only ? 0 : xloc.line);
58838fd1498Szrj       if (xloc.file)
58938fd1498Szrj 	chksum = coverage_checksum_string (chksum, xloc.file);
59038fd1498Szrj       chksum = coverage_checksum_string
59138fd1498Szrj 	(chksum, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (n->decl)));
59238fd1498Szrj       if (!use_name_only && first_global_object_name)
59338fd1498Szrj 	chksum = coverage_checksum_string
59438fd1498Szrj 	  (chksum, first_global_object_name);
59538fd1498Szrj       chksum = coverage_checksum_string
59638fd1498Szrj 	(chksum, aux_base_name);
59738fd1498Szrj     }
59838fd1498Szrj 
59938fd1498Szrj   /* Non-negative integers are hopefully small enough to fit in all targets.
60038fd1498Szrj      Gcov file formats wants non-zero function IDs.  */
60138fd1498Szrj   chksum = chksum & 0x7fffffff;
60238fd1498Szrj   return chksum + (!chksum);
60338fd1498Szrj }
60438fd1498Szrj 
60538fd1498Szrj /* Compute cfg checksum for the function FN given as argument.
60638fd1498Szrj    The checksum is calculated carefully so that
60738fd1498Szrj    source code changes that doesn't affect the control flow graph
60838fd1498Szrj    won't change the checksum.
60938fd1498Szrj    This is to make the profile data useable across source code change.
61038fd1498Szrj    The downside of this is that the compiler may use potentially
61138fd1498Szrj    wrong profile data - that the source code change has non-trivial impact
61238fd1498Szrj    on the validity of profile data (e.g. the reversed condition)
61338fd1498Szrj    but the compiler won't detect the change and use the wrong profile data.  */
61438fd1498Szrj 
61538fd1498Szrj unsigned
coverage_compute_cfg_checksum(struct function * fn)61638fd1498Szrj coverage_compute_cfg_checksum (struct function *fn)
61738fd1498Szrj {
61838fd1498Szrj   basic_block bb;
61938fd1498Szrj   unsigned chksum = n_basic_blocks_for_fn (fn);
62038fd1498Szrj 
62138fd1498Szrj   FOR_EACH_BB_FN (bb, fn)
62238fd1498Szrj     {
62338fd1498Szrj       edge e;
62438fd1498Szrj       edge_iterator ei;
62538fd1498Szrj       chksum = crc32_byte (chksum, bb->index);
62638fd1498Szrj       FOR_EACH_EDGE (e, ei, bb->succs)
62738fd1498Szrj         {
62838fd1498Szrj           chksum = crc32_byte (chksum, e->dest->index);
62938fd1498Szrj         }
63038fd1498Szrj     }
63138fd1498Szrj 
63238fd1498Szrj   return chksum;
63338fd1498Szrj }
63438fd1498Szrj 
63538fd1498Szrj /* Begin output to the notes file for the current function.
63638fd1498Szrj    Writes the function header. Returns nonzero if data should be output.  */
63738fd1498Szrj 
63838fd1498Szrj int
coverage_begin_function(unsigned lineno_checksum,unsigned cfg_checksum)63938fd1498Szrj coverage_begin_function (unsigned lineno_checksum, unsigned cfg_checksum)
64038fd1498Szrj {
64138fd1498Szrj   expanded_location xloc;
64238fd1498Szrj   unsigned long offset;
64338fd1498Szrj 
64438fd1498Szrj   /* We don't need to output .gcno file unless we're under -ftest-coverage
64538fd1498Szrj      (e.g. -fprofile-arcs/generate/use don't need .gcno to work). */
64638fd1498Szrj   if (no_coverage || !bbg_file_name)
64738fd1498Szrj     return 0;
64838fd1498Szrj 
64938fd1498Szrj   xloc = expand_location (DECL_SOURCE_LOCATION (current_function_decl));
65038fd1498Szrj 
65138fd1498Szrj   /* Announce function */
65238fd1498Szrj   offset = gcov_write_tag (GCOV_TAG_FUNCTION);
65338fd1498Szrj   if (PARAM_VALUE (PARAM_PROFILE_FUNC_INTERNAL_ID))
65438fd1498Szrj     gcov_write_unsigned (current_function_funcdef_no + 1);
65538fd1498Szrj   else
65638fd1498Szrj     {
65738fd1498Szrj       gcc_assert (coverage_node_map_initialized_p ());
65838fd1498Szrj       gcov_write_unsigned (
65938fd1498Szrj         cgraph_node::get (current_function_decl)->profile_id);
66038fd1498Szrj     }
66138fd1498Szrj 
66238fd1498Szrj   gcov_write_unsigned (lineno_checksum);
66338fd1498Szrj   gcov_write_unsigned (cfg_checksum);
66438fd1498Szrj   gcov_write_string (IDENTIFIER_POINTER
66538fd1498Szrj 		     (DECL_ASSEMBLER_NAME (current_function_decl)));
666*58e805e6Szrj   gcov_write_unsigned (DECL_ARTIFICIAL (current_function_decl)
667*58e805e6Szrj 		       && !DECL_LAMBDA_FUNCTION (current_function_decl));
66838fd1498Szrj   gcov_write_filename (xloc.file);
66938fd1498Szrj   gcov_write_unsigned (xloc.line);
67038fd1498Szrj   gcov_write_unsigned (xloc.column);
67138fd1498Szrj 
67238fd1498Szrj   expanded_location endloc = expand_location (cfun->function_end_locus);
67338fd1498Szrj 
67438fd1498Szrj   /* Function can start in a single file and end in another one.  */
675*58e805e6Szrj   /* Work-around for PR gcov-profile/88045.  */
676*58e805e6Szrj   int end_line = endloc.file == xloc.file ? endloc.line : xloc.line;
677*58e805e6Szrj   if (xloc.line > end_line)
678*58e805e6Szrj     end_line = xloc.line;
679*58e805e6Szrj   gcov_write_unsigned (end_line);
68038fd1498Szrj   gcov_write_length (offset);
68138fd1498Szrj 
68238fd1498Szrj   return !gcov_is_error ();
68338fd1498Szrj }
68438fd1498Szrj 
68538fd1498Szrj /* Finish coverage data for the current function. Verify no output
68638fd1498Szrj    error has occurred.  Save function coverage counts.  */
68738fd1498Szrj 
68838fd1498Szrj void
coverage_end_function(unsigned lineno_checksum,unsigned cfg_checksum)68938fd1498Szrj coverage_end_function (unsigned lineno_checksum, unsigned cfg_checksum)
69038fd1498Szrj {
69138fd1498Szrj   unsigned i;
69238fd1498Szrj 
69338fd1498Szrj   if (bbg_file_name && gcov_is_error ())
69438fd1498Szrj     {
69538fd1498Szrj       warning (0, "error writing %qs", bbg_file_name);
69638fd1498Szrj       unlink (bbg_file_name);
69738fd1498Szrj       bbg_file_name = NULL;
69838fd1498Szrj     }
69938fd1498Szrj 
70038fd1498Szrj   if (fn_ctr_mask)
70138fd1498Szrj     {
70238fd1498Szrj       struct coverage_data *item = 0;
70338fd1498Szrj 
70438fd1498Szrj       item = ggc_alloc<coverage_data> ();
70538fd1498Szrj 
70638fd1498Szrj       if (PARAM_VALUE (PARAM_PROFILE_FUNC_INTERNAL_ID))
70738fd1498Szrj 	item->ident = current_function_funcdef_no + 1;
70838fd1498Szrj       else
70938fd1498Szrj 	{
71038fd1498Szrj 	  gcc_assert (coverage_node_map_initialized_p ());
71138fd1498Szrj 	  item->ident = cgraph_node::get (cfun->decl)->profile_id;
71238fd1498Szrj 	}
71338fd1498Szrj 
71438fd1498Szrj       item->lineno_checksum = lineno_checksum;
71538fd1498Szrj       item->cfg_checksum = cfg_checksum;
71638fd1498Szrj 
71738fd1498Szrj       item->fn_decl = current_function_decl;
71838fd1498Szrj       item->next = 0;
71938fd1498Szrj       *functions_tail = item;
72038fd1498Szrj       functions_tail = &item->next;
72138fd1498Szrj 
72238fd1498Szrj       for (i = 0; i != GCOV_COUNTERS; i++)
72338fd1498Szrj 	{
72438fd1498Szrj 	  tree var = fn_v_ctrs[i];
72538fd1498Szrj 
72638fd1498Szrj 	  if (item)
72738fd1498Szrj 	    item->ctr_vars[i] = var;
72838fd1498Szrj 	  if (var)
72938fd1498Szrj 	    {
73038fd1498Szrj 	      tree array_type = build_index_type (size_int (fn_n_ctrs[i] - 1));
73138fd1498Szrj 	      array_type = build_array_type (get_gcov_type (), array_type);
73238fd1498Szrj 	      TREE_TYPE (var) = array_type;
73338fd1498Szrj 	      DECL_SIZE (var) = TYPE_SIZE (array_type);
73438fd1498Szrj 	      DECL_SIZE_UNIT (var) = TYPE_SIZE_UNIT (array_type);
73538fd1498Szrj 	      varpool_node::finalize_decl (var);
73638fd1498Szrj 	    }
73738fd1498Szrj 
73838fd1498Szrj 	  fn_b_ctrs[i] = fn_n_ctrs[i] = 0;
73938fd1498Szrj 	  fn_v_ctrs[i] = NULL_TREE;
74038fd1498Szrj 	}
74138fd1498Szrj       prg_ctr_mask |= fn_ctr_mask;
74238fd1498Szrj       fn_ctr_mask = 0;
74338fd1498Szrj     }
74438fd1498Szrj }
74538fd1498Szrj 
74638fd1498Szrj /* Remove coverage file if opened.  */
74738fd1498Szrj 
74838fd1498Szrj void
coverage_remove_note_file(void)74938fd1498Szrj coverage_remove_note_file (void)
75038fd1498Szrj {
75138fd1498Szrj   if (bbg_file_name)
75238fd1498Szrj     {
75338fd1498Szrj       gcov_close ();
75438fd1498Szrj       unlink (bbg_file_name);
75538fd1498Szrj     }
75638fd1498Szrj }
75738fd1498Szrj 
75838fd1498Szrj /* Build a coverage variable of TYPE for function FN_DECL.  If COUNTER
75938fd1498Szrj    >= 0 it is a counter array, otherwise it is the function structure.  */
76038fd1498Szrj 
76138fd1498Szrj static tree
build_var(tree fn_decl,tree type,int counter)76238fd1498Szrj build_var (tree fn_decl, tree type, int counter)
76338fd1498Szrj {
76438fd1498Szrj   tree var = build_decl (BUILTINS_LOCATION, VAR_DECL, NULL_TREE, type);
76538fd1498Szrj   const char *fn_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fn_decl));
76638fd1498Szrj   char *buf;
76738fd1498Szrj   size_t fn_name_len, len;
76838fd1498Szrj 
76938fd1498Szrj   fn_name = targetm.strip_name_encoding (fn_name);
77038fd1498Szrj   fn_name_len = strlen (fn_name);
77138fd1498Szrj   buf = XALLOCAVEC (char, fn_name_len + 8 + sizeof (int) * 3);
77238fd1498Szrj 
77338fd1498Szrj   if (counter < 0)
77438fd1498Szrj     strcpy (buf, "__gcov__");
77538fd1498Szrj   else
77638fd1498Szrj     sprintf (buf, "__gcov%u_", counter);
77738fd1498Szrj   len = strlen (buf);
77838fd1498Szrj   buf[len - 1] = symbol_table::symbol_suffix_separator ();
77938fd1498Szrj   memcpy (buf + len, fn_name, fn_name_len + 1);
78038fd1498Szrj   DECL_NAME (var) = get_identifier (buf);
78138fd1498Szrj   TREE_STATIC (var) = 1;
78238fd1498Szrj   TREE_ADDRESSABLE (var) = 1;
78338fd1498Szrj   DECL_NONALIASED (var) = 1;
78438fd1498Szrj   SET_DECL_ALIGN (var, TYPE_ALIGN (type));
78538fd1498Szrj 
78638fd1498Szrj   return var;
78738fd1498Szrj }
78838fd1498Szrj 
78938fd1498Szrj /* Creates the gcov_fn_info RECORD_TYPE.  */
79038fd1498Szrj 
79138fd1498Szrj static void
build_fn_info_type(tree type,unsigned counters,tree gcov_info_type)79238fd1498Szrj build_fn_info_type (tree type, unsigned counters, tree gcov_info_type)
79338fd1498Szrj {
79438fd1498Szrj   tree ctr_info = lang_hooks.types.make_type (RECORD_TYPE);
79538fd1498Szrj   tree field, fields;
79638fd1498Szrj   tree array_type;
79738fd1498Szrj 
79838fd1498Szrj   gcc_assert (counters);
79938fd1498Szrj 
80038fd1498Szrj   /* ctr_info::num */
80138fd1498Szrj   field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
80238fd1498Szrj 		      get_gcov_unsigned_t ());
80338fd1498Szrj   fields = field;
80438fd1498Szrj 
80538fd1498Szrj   /* ctr_info::values */
80638fd1498Szrj   field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
80738fd1498Szrj 		      build_pointer_type (get_gcov_type ()));
80838fd1498Szrj   DECL_CHAIN (field) = fields;
80938fd1498Szrj   fields = field;
81038fd1498Szrj 
81138fd1498Szrj   finish_builtin_struct (ctr_info, "__gcov_ctr_info", fields, NULL_TREE);
81238fd1498Szrj 
81338fd1498Szrj   /* key */
81438fd1498Szrj   field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
81538fd1498Szrj 		      build_pointer_type (build_qualified_type
81638fd1498Szrj 					  (gcov_info_type, TYPE_QUAL_CONST)));
81738fd1498Szrj   fields = field;
81838fd1498Szrj 
81938fd1498Szrj   /* ident */
82038fd1498Szrj   field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
82138fd1498Szrj 		      get_gcov_unsigned_t ());
82238fd1498Szrj   DECL_CHAIN (field) = fields;
82338fd1498Szrj   fields = field;
82438fd1498Szrj 
82538fd1498Szrj   /* lineno_checksum */
82638fd1498Szrj   field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
82738fd1498Szrj 		      get_gcov_unsigned_t ());
82838fd1498Szrj   DECL_CHAIN (field) = fields;
82938fd1498Szrj   fields = field;
83038fd1498Szrj 
83138fd1498Szrj   /* cfg checksum */
83238fd1498Szrj   field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
83338fd1498Szrj 		      get_gcov_unsigned_t ());
83438fd1498Szrj   DECL_CHAIN (field) = fields;
83538fd1498Szrj   fields = field;
83638fd1498Szrj 
83738fd1498Szrj   array_type = build_index_type (size_int (counters - 1));
83838fd1498Szrj   array_type = build_array_type (ctr_info, array_type);
83938fd1498Szrj 
84038fd1498Szrj   /* counters */
84138fd1498Szrj   field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE, array_type);
84238fd1498Szrj   DECL_CHAIN (field) = fields;
84338fd1498Szrj   fields = field;
84438fd1498Szrj 
84538fd1498Szrj   finish_builtin_struct (type, "__gcov_fn_info", fields, NULL_TREE);
84638fd1498Szrj }
84738fd1498Szrj 
84838fd1498Szrj /* Returns a CONSTRUCTOR for a gcov_fn_info.  DATA is
84938fd1498Szrj    the coverage data for the function and TYPE is the gcov_fn_info
85038fd1498Szrj    RECORD_TYPE.  KEY is the object file key.  */
85138fd1498Szrj 
85238fd1498Szrj static tree
build_fn_info(const struct coverage_data * data,tree type,tree key)85338fd1498Szrj build_fn_info (const struct coverage_data *data, tree type, tree key)
85438fd1498Szrj {
85538fd1498Szrj   tree fields = TYPE_FIELDS (type);
85638fd1498Szrj   tree ctr_type;
85738fd1498Szrj   unsigned ix;
85838fd1498Szrj   vec<constructor_elt, va_gc> *v1 = NULL;
85938fd1498Szrj   vec<constructor_elt, va_gc> *v2 = NULL;
86038fd1498Szrj 
86138fd1498Szrj   /* key */
86238fd1498Szrj   CONSTRUCTOR_APPEND_ELT (v1, fields,
86338fd1498Szrj 			  build1 (ADDR_EXPR, TREE_TYPE (fields), key));
86438fd1498Szrj   fields = DECL_CHAIN (fields);
86538fd1498Szrj 
86638fd1498Szrj   /* ident */
86738fd1498Szrj   CONSTRUCTOR_APPEND_ELT (v1, fields,
86838fd1498Szrj 			  build_int_cstu (get_gcov_unsigned_t (),
86938fd1498Szrj 					  data->ident));
87038fd1498Szrj   fields = DECL_CHAIN (fields);
87138fd1498Szrj 
87238fd1498Szrj   /* lineno_checksum */
87338fd1498Szrj   CONSTRUCTOR_APPEND_ELT (v1, fields,
87438fd1498Szrj 			  build_int_cstu (get_gcov_unsigned_t (),
87538fd1498Szrj 					  data->lineno_checksum));
87638fd1498Szrj   fields = DECL_CHAIN (fields);
87738fd1498Szrj 
87838fd1498Szrj   /* cfg_checksum */
87938fd1498Szrj   CONSTRUCTOR_APPEND_ELT (v1, fields,
88038fd1498Szrj 			  build_int_cstu (get_gcov_unsigned_t (),
88138fd1498Szrj 					  data->cfg_checksum));
88238fd1498Szrj   fields = DECL_CHAIN (fields);
88338fd1498Szrj 
88438fd1498Szrj   /* counters */
88538fd1498Szrj   ctr_type = TREE_TYPE (TREE_TYPE (fields));
88638fd1498Szrj   for (ix = 0; ix != GCOV_COUNTERS; ix++)
88738fd1498Szrj     if (prg_ctr_mask & (1 << ix))
88838fd1498Szrj       {
88938fd1498Szrj 	vec<constructor_elt, va_gc> *ctr = NULL;
89038fd1498Szrj 	tree var = data->ctr_vars[ix];
89138fd1498Szrj 	unsigned count = 0;
89238fd1498Szrj 
89338fd1498Szrj 	if (var)
89438fd1498Szrj 	  count
89538fd1498Szrj 	    = tree_to_shwi (TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (var))))
89638fd1498Szrj 	    + 1;
89738fd1498Szrj 
89838fd1498Szrj 	CONSTRUCTOR_APPEND_ELT (ctr, TYPE_FIELDS (ctr_type),
89938fd1498Szrj 				build_int_cstu (get_gcov_unsigned_t (),
90038fd1498Szrj 						count));
90138fd1498Szrj 
90238fd1498Szrj 	if (var)
90338fd1498Szrj 	  CONSTRUCTOR_APPEND_ELT (ctr, DECL_CHAIN (TYPE_FIELDS (ctr_type)),
90438fd1498Szrj 				  build_fold_addr_expr (var));
90538fd1498Szrj 
90638fd1498Szrj 	CONSTRUCTOR_APPEND_ELT (v2, NULL, build_constructor (ctr_type, ctr));
90738fd1498Szrj       }
90838fd1498Szrj 
90938fd1498Szrj   CONSTRUCTOR_APPEND_ELT (v1, fields,
91038fd1498Szrj 			  build_constructor (TREE_TYPE (fields), v2));
91138fd1498Szrj 
91238fd1498Szrj   return build_constructor (type, v1);
91338fd1498Szrj }
91438fd1498Szrj 
91538fd1498Szrj /* Create gcov_info struct.  TYPE is the incomplete RECORD_TYPE to be
91638fd1498Szrj    completed, and FN_INFO_PTR_TYPE is a pointer to the function info type.  */
91738fd1498Szrj 
91838fd1498Szrj static void
build_info_type(tree type,tree fn_info_ptr_type)91938fd1498Szrj build_info_type (tree type, tree fn_info_ptr_type)
92038fd1498Szrj {
92138fd1498Szrj   tree field, fields = NULL_TREE;
92238fd1498Szrj   tree merge_fn_type;
92338fd1498Szrj 
92438fd1498Szrj   /* Version ident */
92538fd1498Szrj   field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
92638fd1498Szrj 		      get_gcov_unsigned_t ());
92738fd1498Szrj   DECL_CHAIN (field) = fields;
92838fd1498Szrj   fields = field;
92938fd1498Szrj 
93038fd1498Szrj   /* next pointer */
93138fd1498Szrj   field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
93238fd1498Szrj 		      build_pointer_type (build_qualified_type
93338fd1498Szrj 					  (type, TYPE_QUAL_CONST)));
93438fd1498Szrj   DECL_CHAIN (field) = fields;
93538fd1498Szrj   fields = field;
93638fd1498Szrj 
93738fd1498Szrj   /* stamp */
93838fd1498Szrj   field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
93938fd1498Szrj 		      get_gcov_unsigned_t ());
94038fd1498Szrj   DECL_CHAIN (field) = fields;
94138fd1498Szrj   fields = field;
94238fd1498Szrj 
94338fd1498Szrj   /* Filename */
94438fd1498Szrj   field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
94538fd1498Szrj 		      build_pointer_type (build_qualified_type
94638fd1498Szrj 					  (char_type_node, TYPE_QUAL_CONST)));
94738fd1498Szrj   DECL_CHAIN (field) = fields;
94838fd1498Szrj   fields = field;
94938fd1498Szrj 
95038fd1498Szrj   /* merge fn array */
95138fd1498Szrj   merge_fn_type
95238fd1498Szrj     = build_function_type_list (void_type_node,
95338fd1498Szrj 				build_pointer_type (get_gcov_type ()),
95438fd1498Szrj 				get_gcov_unsigned_t (), NULL_TREE);
95538fd1498Szrj   merge_fn_type
95638fd1498Szrj     = build_array_type (build_pointer_type (merge_fn_type),
95738fd1498Szrj 			build_index_type (size_int (GCOV_COUNTERS - 1)));
95838fd1498Szrj   field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
95938fd1498Szrj 		      merge_fn_type);
96038fd1498Szrj   DECL_CHAIN (field) = fields;
96138fd1498Szrj   fields = field;
96238fd1498Szrj 
96338fd1498Szrj   /* n_functions */
96438fd1498Szrj   field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
96538fd1498Szrj 		      get_gcov_unsigned_t ());
96638fd1498Szrj   DECL_CHAIN (field) = fields;
96738fd1498Szrj   fields = field;
96838fd1498Szrj 
96938fd1498Szrj   /* function_info pointer pointer */
97038fd1498Szrj   fn_info_ptr_type = build_pointer_type
97138fd1498Szrj     (build_qualified_type (fn_info_ptr_type, TYPE_QUAL_CONST));
97238fd1498Szrj   field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
97338fd1498Szrj 		      fn_info_ptr_type);
97438fd1498Szrj   DECL_CHAIN (field) = fields;
97538fd1498Szrj   fields = field;
97638fd1498Szrj 
97738fd1498Szrj   finish_builtin_struct (type, "__gcov_info", fields, NULL_TREE);
97838fd1498Szrj }
97938fd1498Szrj 
98038fd1498Szrj /* Returns a CONSTRUCTOR for the gcov_info object.  INFO_TYPE is the
98138fd1498Szrj    gcov_info structure type, FN_ARY is the array of pointers to
98238fd1498Szrj    function info objects.  */
98338fd1498Szrj 
98438fd1498Szrj static tree
build_info(tree info_type,tree fn_ary)98538fd1498Szrj build_info (tree info_type, tree fn_ary)
98638fd1498Szrj {
98738fd1498Szrj   tree info_fields = TYPE_FIELDS (info_type);
98838fd1498Szrj   tree merge_fn_type, n_funcs;
98938fd1498Szrj   unsigned ix;
99038fd1498Szrj   tree filename_string;
99138fd1498Szrj   int da_file_name_len;
99238fd1498Szrj   vec<constructor_elt, va_gc> *v1 = NULL;
99338fd1498Szrj   vec<constructor_elt, va_gc> *v2 = NULL;
99438fd1498Szrj 
99538fd1498Szrj   /* Version ident */
99638fd1498Szrj   CONSTRUCTOR_APPEND_ELT (v1, info_fields,
99738fd1498Szrj 			  build_int_cstu (TREE_TYPE (info_fields),
99838fd1498Szrj 					  GCOV_VERSION));
99938fd1498Szrj   info_fields = DECL_CHAIN (info_fields);
100038fd1498Szrj 
100138fd1498Szrj   /* next -- NULL */
100238fd1498Szrj   CONSTRUCTOR_APPEND_ELT (v1, info_fields, null_pointer_node);
100338fd1498Szrj   info_fields = DECL_CHAIN (info_fields);
100438fd1498Szrj 
100538fd1498Szrj   /* stamp */
100638fd1498Szrj   CONSTRUCTOR_APPEND_ELT (v1, info_fields,
100738fd1498Szrj 			  build_int_cstu (TREE_TYPE (info_fields),
100838fd1498Szrj 					  bbg_file_stamp));
100938fd1498Szrj   info_fields = DECL_CHAIN (info_fields);
101038fd1498Szrj 
101138fd1498Szrj   /* Filename */
101238fd1498Szrj   da_file_name_len = strlen (da_file_name);
101338fd1498Szrj   filename_string = build_string (da_file_name_len + 1, da_file_name);
101438fd1498Szrj   TREE_TYPE (filename_string) = build_array_type
101538fd1498Szrj     (char_type_node, build_index_type (size_int (da_file_name_len)));
101638fd1498Szrj   CONSTRUCTOR_APPEND_ELT (v1, info_fields,
101738fd1498Szrj 			  build1 (ADDR_EXPR, TREE_TYPE (info_fields),
101838fd1498Szrj 				  filename_string));
101938fd1498Szrj   info_fields = DECL_CHAIN (info_fields);
102038fd1498Szrj 
102138fd1498Szrj   /* merge fn array -- NULL slots indicate unmeasured counters */
102238fd1498Szrj   merge_fn_type = TREE_TYPE (TREE_TYPE (info_fields));
102338fd1498Szrj   for (ix = 0; ix != GCOV_COUNTERS; ix++)
102438fd1498Szrj     {
102538fd1498Szrj       tree ptr = null_pointer_node;
102638fd1498Szrj 
102738fd1498Szrj       if ((1u << ix) & prg_ctr_mask)
102838fd1498Szrj 	{
102938fd1498Szrj 	  tree merge_fn = build_decl (BUILTINS_LOCATION,
103038fd1498Szrj 				      FUNCTION_DECL,
103138fd1498Szrj 				      get_identifier (ctr_merge_functions[ix]),
103238fd1498Szrj 				      TREE_TYPE (merge_fn_type));
103338fd1498Szrj 	  DECL_EXTERNAL (merge_fn) = 1;
103438fd1498Szrj 	  TREE_PUBLIC (merge_fn) = 1;
103538fd1498Szrj 	  DECL_ARTIFICIAL (merge_fn) = 1;
103638fd1498Szrj 	  TREE_NOTHROW (merge_fn) = 1;
103738fd1498Szrj 	  /* Initialize assembler name so we can stream out. */
103838fd1498Szrj 	  DECL_ASSEMBLER_NAME (merge_fn);
103938fd1498Szrj 	  ptr = build1 (ADDR_EXPR, merge_fn_type, merge_fn);
104038fd1498Szrj 	}
104138fd1498Szrj       CONSTRUCTOR_APPEND_ELT (v2, NULL, ptr);
104238fd1498Szrj     }
104338fd1498Szrj   CONSTRUCTOR_APPEND_ELT (v1, info_fields,
104438fd1498Szrj 			  build_constructor (TREE_TYPE (info_fields), v2));
104538fd1498Szrj   info_fields = DECL_CHAIN (info_fields);
104638fd1498Szrj 
104738fd1498Szrj   /* n_functions */
104838fd1498Szrj   n_funcs = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (fn_ary)));
104938fd1498Szrj   n_funcs = fold_build2 (PLUS_EXPR, TREE_TYPE (info_fields),
105038fd1498Szrj 			 n_funcs, size_one_node);
105138fd1498Szrj   CONSTRUCTOR_APPEND_ELT (v1, info_fields, n_funcs);
105238fd1498Szrj   info_fields = DECL_CHAIN (info_fields);
105338fd1498Szrj 
105438fd1498Szrj   /* functions */
105538fd1498Szrj   CONSTRUCTOR_APPEND_ELT (v1, info_fields,
105638fd1498Szrj 			  build1 (ADDR_EXPR, TREE_TYPE (info_fields), fn_ary));
105738fd1498Szrj   info_fields = DECL_CHAIN (info_fields);
105838fd1498Szrj 
105938fd1498Szrj   gcc_assert (!info_fields);
106038fd1498Szrj   return build_constructor (info_type, v1);
106138fd1498Szrj }
106238fd1498Szrj 
106338fd1498Szrj /* Generate the constructor function to call __gcov_init.  */
106438fd1498Szrj 
106538fd1498Szrj static void
build_init_ctor(tree gcov_info_type)106638fd1498Szrj build_init_ctor (tree gcov_info_type)
106738fd1498Szrj {
106838fd1498Szrj   tree ctor, stmt, init_fn;
106938fd1498Szrj 
107038fd1498Szrj   /* Build a decl for __gcov_init.  */
107138fd1498Szrj   init_fn = build_pointer_type (gcov_info_type);
107238fd1498Szrj   init_fn = build_function_type_list (void_type_node, init_fn, NULL);
107338fd1498Szrj   init_fn = build_decl (BUILTINS_LOCATION, FUNCTION_DECL,
107438fd1498Szrj 			get_identifier ("__gcov_init"), init_fn);
107538fd1498Szrj   TREE_PUBLIC (init_fn) = 1;
107638fd1498Szrj   DECL_EXTERNAL (init_fn) = 1;
107738fd1498Szrj   DECL_ASSEMBLER_NAME (init_fn);
107838fd1498Szrj 
107938fd1498Szrj   /* Generate a call to __gcov_init(&gcov_info).  */
108038fd1498Szrj   ctor = NULL;
108138fd1498Szrj   stmt = build_fold_addr_expr (gcov_info_var);
108238fd1498Szrj   stmt = build_call_expr (init_fn, 1, stmt);
108338fd1498Szrj   append_to_statement_list (stmt, &ctor);
108438fd1498Szrj 
108538fd1498Szrj   /* Generate a constructor to run it.  */
108638fd1498Szrj   int priority = SUPPORTS_INIT_PRIORITY
108738fd1498Szrj     ? MAX_RESERVED_INIT_PRIORITY: DEFAULT_INIT_PRIORITY;
108838fd1498Szrj   cgraph_build_static_cdtor ('I', ctor, priority);
108938fd1498Szrj }
109038fd1498Szrj 
109138fd1498Szrj /* Generate the destructor function to call __gcov_exit.  */
109238fd1498Szrj 
109338fd1498Szrj static void
build_gcov_exit_decl(void)109438fd1498Szrj build_gcov_exit_decl (void)
109538fd1498Szrj {
109638fd1498Szrj   tree init_fn = build_function_type_list (void_type_node, void_type_node,
109738fd1498Szrj 					   NULL);
109838fd1498Szrj   init_fn = build_decl (BUILTINS_LOCATION, FUNCTION_DECL,
109938fd1498Szrj 			get_identifier ("__gcov_exit"), init_fn);
110038fd1498Szrj   TREE_PUBLIC (init_fn) = 1;
110138fd1498Szrj   DECL_EXTERNAL (init_fn) = 1;
110238fd1498Szrj   DECL_ASSEMBLER_NAME (init_fn);
110338fd1498Szrj 
110438fd1498Szrj   /* Generate a call to __gcov_exit ().  */
110538fd1498Szrj   tree dtor = NULL;
110638fd1498Szrj   tree stmt = build_call_expr (init_fn, 0);
110738fd1498Szrj   append_to_statement_list (stmt, &dtor);
110838fd1498Szrj 
110938fd1498Szrj   /* Generate a destructor to run it.  */
111038fd1498Szrj   int priority = SUPPORTS_INIT_PRIORITY
111138fd1498Szrj     ? MAX_RESERVED_INIT_PRIORITY: DEFAULT_INIT_PRIORITY;
111238fd1498Szrj 
111338fd1498Szrj   cgraph_build_static_cdtor ('D', dtor, priority);
111438fd1498Szrj }
111538fd1498Szrj 
111638fd1498Szrj /* Create the gcov_info types and object.  Generate the constructor
111738fd1498Szrj    function to call __gcov_init.  Does not generate the initializer
111838fd1498Szrj    for the object.  Returns TRUE if coverage data is being emitted.  */
111938fd1498Szrj 
112038fd1498Szrj static bool
coverage_obj_init(void)112138fd1498Szrj coverage_obj_init (void)
112238fd1498Szrj {
112338fd1498Szrj   tree gcov_info_type;
112438fd1498Szrj   unsigned n_counters = 0;
112538fd1498Szrj   unsigned ix;
112638fd1498Szrj   struct coverage_data *fn;
112738fd1498Szrj   struct coverage_data **fn_prev;
112838fd1498Szrj   char name_buf[32];
112938fd1498Szrj 
113038fd1498Szrj   no_coverage = 1; /* Disable any further coverage.  */
113138fd1498Szrj 
113238fd1498Szrj   if (!prg_ctr_mask)
113338fd1498Szrj     return false;
113438fd1498Szrj 
113538fd1498Szrj   if (symtab->dump_file)
113638fd1498Szrj     fprintf (symtab->dump_file, "Using data file %s\n", da_file_name);
113738fd1498Szrj 
113838fd1498Szrj   /* Prune functions.  */
113938fd1498Szrj   for (fn_prev = &functions_head; (fn = *fn_prev);)
114038fd1498Szrj     if (DECL_STRUCT_FUNCTION (fn->fn_decl))
114138fd1498Szrj       fn_prev = &fn->next;
114238fd1498Szrj     else
114338fd1498Szrj       /* The function is not being emitted, remove from list.  */
114438fd1498Szrj       *fn_prev = fn->next;
114538fd1498Szrj 
114638fd1498Szrj   if (functions_head == NULL)
114738fd1498Szrj     return false;
114838fd1498Szrj 
114938fd1498Szrj   for (ix = 0; ix != GCOV_COUNTERS; ix++)
115038fd1498Szrj     if ((1u << ix) & prg_ctr_mask)
115138fd1498Szrj       n_counters++;
115238fd1498Szrj 
115338fd1498Szrj   /* Build the info and fn_info types.  These are mutually recursive.  */
115438fd1498Szrj   gcov_info_type = lang_hooks.types.make_type (RECORD_TYPE);
115538fd1498Szrj   gcov_fn_info_type = lang_hooks.types.make_type (RECORD_TYPE);
115638fd1498Szrj   build_fn_info_type (gcov_fn_info_type, n_counters, gcov_info_type);
115738fd1498Szrj   gcov_info_type = lang_hooks.types.make_type (RECORD_TYPE);
115838fd1498Szrj   gcov_fn_info_ptr_type = build_pointer_type
115938fd1498Szrj     (build_qualified_type (gcov_fn_info_type, TYPE_QUAL_CONST));
116038fd1498Szrj   build_info_type (gcov_info_type, gcov_fn_info_ptr_type);
116138fd1498Szrj 
116238fd1498Szrj   /* Build the gcov info var, this is referred to in its own
116338fd1498Szrj      initializer.  */
116438fd1498Szrj   gcov_info_var = build_decl (BUILTINS_LOCATION,
116538fd1498Szrj 			      VAR_DECL, NULL_TREE, gcov_info_type);
116638fd1498Szrj   TREE_STATIC (gcov_info_var) = 1;
116738fd1498Szrj   ASM_GENERATE_INTERNAL_LABEL (name_buf, "LPBX", 0);
116838fd1498Szrj   DECL_NAME (gcov_info_var) = get_identifier (name_buf);
116938fd1498Szrj 
117038fd1498Szrj   build_init_ctor (gcov_info_type);
117138fd1498Szrj   build_gcov_exit_decl ();
117238fd1498Szrj 
117338fd1498Szrj   return true;
117438fd1498Szrj }
117538fd1498Szrj 
117638fd1498Szrj /* Generate the coverage function info for FN and DATA.  Append a
117738fd1498Szrj    pointer to that object to CTOR and return the appended CTOR.  */
117838fd1498Szrj 
117938fd1498Szrj static vec<constructor_elt, va_gc> *
coverage_obj_fn(vec<constructor_elt,va_gc> * ctor,tree fn,struct coverage_data const * data)118038fd1498Szrj coverage_obj_fn (vec<constructor_elt, va_gc> *ctor, tree fn,
118138fd1498Szrj 		 struct coverage_data const *data)
118238fd1498Szrj {
118338fd1498Szrj   tree init = build_fn_info (data, gcov_fn_info_type, gcov_info_var);
118438fd1498Szrj   tree var = build_var (fn, gcov_fn_info_type, -1);
118538fd1498Szrj 
118638fd1498Szrj   DECL_INITIAL (var) = init;
118738fd1498Szrj   varpool_node::finalize_decl (var);
118838fd1498Szrj 
118938fd1498Szrj   CONSTRUCTOR_APPEND_ELT (ctor, NULL,
119038fd1498Szrj 			  build1 (ADDR_EXPR, gcov_fn_info_ptr_type, var));
119138fd1498Szrj   return ctor;
119238fd1498Szrj }
119338fd1498Szrj 
119438fd1498Szrj /* Finalize the coverage data.  Generates the array of pointers to
119538fd1498Szrj    function objects from CTOR.  Generate the gcov_info initializer.  */
119638fd1498Szrj 
119738fd1498Szrj static void
coverage_obj_finish(vec<constructor_elt,va_gc> * ctor)119838fd1498Szrj coverage_obj_finish (vec<constructor_elt, va_gc> *ctor)
119938fd1498Szrj {
120038fd1498Szrj   unsigned n_functions = vec_safe_length (ctor);
120138fd1498Szrj   tree fn_info_ary_type = build_array_type
120238fd1498Szrj     (build_qualified_type (gcov_fn_info_ptr_type, TYPE_QUAL_CONST),
120338fd1498Szrj      build_index_type (size_int (n_functions - 1)));
120438fd1498Szrj   tree fn_info_ary = build_decl (BUILTINS_LOCATION, VAR_DECL, NULL_TREE,
120538fd1498Szrj 				 fn_info_ary_type);
120638fd1498Szrj   char name_buf[32];
120738fd1498Szrj 
120838fd1498Szrj   TREE_STATIC (fn_info_ary) = 1;
120938fd1498Szrj   ASM_GENERATE_INTERNAL_LABEL (name_buf, "LPBX", 1);
121038fd1498Szrj   DECL_NAME (fn_info_ary) = get_identifier (name_buf);
121138fd1498Szrj   DECL_INITIAL (fn_info_ary) = build_constructor (fn_info_ary_type, ctor);
121238fd1498Szrj   varpool_node::finalize_decl (fn_info_ary);
121338fd1498Szrj 
121438fd1498Szrj   DECL_INITIAL (gcov_info_var)
121538fd1498Szrj     = build_info (TREE_TYPE (gcov_info_var), fn_info_ary);
121638fd1498Szrj   varpool_node::finalize_decl (gcov_info_var);
121738fd1498Szrj }
121838fd1498Szrj 
121938fd1498Szrj /* Perform file-level initialization. Read in data file, generate name
122038fd1498Szrj    of notes file.  */
122138fd1498Szrj 
122238fd1498Szrj void
coverage_init(const char * filename)122338fd1498Szrj coverage_init (const char *filename)
122438fd1498Szrj {
122538fd1498Szrj   int len = strlen (filename);
122638fd1498Szrj   int prefix_len = 0;
122738fd1498Szrj 
122838fd1498Szrj   /* Since coverage_init is invoked very early, before the pass
122938fd1498Szrj      manager, we need to set up the dumping explicitly. This is
123038fd1498Szrj      similar to the handling in finish_optimization_passes.  */
123138fd1498Szrj   int profile_pass_num =
123238fd1498Szrj     g->get_passes ()->get_pass_profile ()->static_pass_number;
123338fd1498Szrj   g->get_dumps ()->dump_start (profile_pass_num, NULL);
123438fd1498Szrj 
123538fd1498Szrj   if (!profile_data_prefix && !IS_ABSOLUTE_PATH (filename))
123638fd1498Szrj     profile_data_prefix = getpwd ();
123738fd1498Szrj 
123838fd1498Szrj   if (profile_data_prefix)
123938fd1498Szrj     prefix_len = strlen (profile_data_prefix);
124038fd1498Szrj 
124138fd1498Szrj   /* Name of da file.  */
124238fd1498Szrj   da_file_name = XNEWVEC (char, len + strlen (GCOV_DATA_SUFFIX)
124338fd1498Szrj 			  + prefix_len + 2);
124438fd1498Szrj 
124538fd1498Szrj   if (profile_data_prefix)
124638fd1498Szrj     {
124738fd1498Szrj       memcpy (da_file_name, profile_data_prefix, prefix_len);
124838fd1498Szrj       da_file_name[prefix_len++] = '/';
124938fd1498Szrj     }
125038fd1498Szrj   memcpy (da_file_name + prefix_len, filename, len);
125138fd1498Szrj   strcpy (da_file_name + prefix_len + len, GCOV_DATA_SUFFIX);
125238fd1498Szrj 
125338fd1498Szrj   bbg_file_stamp = local_tick;
125438fd1498Szrj 
125538fd1498Szrj   if (flag_auto_profile)
125638fd1498Szrj     read_autofdo_file ();
125738fd1498Szrj   else if (flag_branch_probabilities)
125838fd1498Szrj     read_counts_file ();
125938fd1498Szrj 
126038fd1498Szrj   /* Name of bbg file.  */
126138fd1498Szrj   if (flag_test_coverage && !flag_compare_debug)
126238fd1498Szrj     {
126338fd1498Szrj       bbg_file_name = XNEWVEC (char, len + strlen (GCOV_NOTE_SUFFIX) + 1);
126438fd1498Szrj       memcpy (bbg_file_name, filename, len);
126538fd1498Szrj       strcpy (bbg_file_name + len, GCOV_NOTE_SUFFIX);
126638fd1498Szrj 
126738fd1498Szrj       if (!gcov_open (bbg_file_name, -1))
126838fd1498Szrj 	{
126938fd1498Szrj 	  error ("cannot open %s", bbg_file_name);
127038fd1498Szrj 	  bbg_file_name = NULL;
127138fd1498Szrj 	}
127238fd1498Szrj       else
127338fd1498Szrj 	{
127438fd1498Szrj 	  gcov_write_unsigned (GCOV_NOTE_MAGIC);
127538fd1498Szrj 	  gcov_write_unsigned (GCOV_VERSION);
127638fd1498Szrj 	  gcov_write_unsigned (bbg_file_stamp);
127738fd1498Szrj 
127838fd1498Szrj 	  /* Do not support has_unexecuted_blocks for Ada.  */
127938fd1498Szrj 	  gcov_write_unsigned (strcmp (lang_hooks.name, "GNU Ada") != 0);
128038fd1498Szrj 	}
128138fd1498Szrj     }
128238fd1498Szrj 
128338fd1498Szrj   g->get_dumps ()->dump_finish (profile_pass_num);
128438fd1498Szrj }
128538fd1498Szrj 
128638fd1498Szrj /* Performs file-level cleanup.  Close notes file, generate coverage
128738fd1498Szrj    variables and constructor.  */
128838fd1498Szrj 
128938fd1498Szrj void
coverage_finish(void)129038fd1498Szrj coverage_finish (void)
129138fd1498Szrj {
129238fd1498Szrj   if (bbg_file_name && gcov_close ())
129338fd1498Szrj     unlink (bbg_file_name);
129438fd1498Szrj 
129538fd1498Szrj   if (!flag_branch_probabilities && flag_test_coverage
129638fd1498Szrj       && (!local_tick || local_tick == (unsigned)-1))
129738fd1498Szrj     /* Only remove the da file, if we're emitting coverage code and
129838fd1498Szrj        cannot uniquely stamp it.  If we can stamp it, libgcov will DTRT.  */
129938fd1498Szrj     unlink (da_file_name);
130038fd1498Szrj 
130138fd1498Szrj   if (coverage_obj_init ())
130238fd1498Szrj     {
130338fd1498Szrj       vec<constructor_elt, va_gc> *fn_ctor = NULL;
130438fd1498Szrj       struct coverage_data *fn;
130538fd1498Szrj 
130638fd1498Szrj       for (fn = functions_head; fn; fn = fn->next)
130738fd1498Szrj 	fn_ctor = coverage_obj_fn (fn_ctor, fn->fn_decl, fn);
130838fd1498Szrj       coverage_obj_finish (fn_ctor);
130938fd1498Szrj     }
131038fd1498Szrj 
131138fd1498Szrj   XDELETEVEC (da_file_name);
131238fd1498Szrj   da_file_name = NULL;
131338fd1498Szrj }
131438fd1498Szrj 
131538fd1498Szrj #include "gt-coverage.h"
1316