xref: /dflybsd-src/contrib/gcc-8.0/gcc/coverage.c (revision 38fd149817dfbff97799f62fcb70be98c4e32523)
1*38fd1498Szrj /* Read and write coverage files, and associated functionality.
2*38fd1498Szrj    Copyright (C) 1990-2018 Free Software Foundation, Inc.
3*38fd1498Szrj    Contributed by James E. Wilson, UC Berkeley/Cygnus Support;
4*38fd1498Szrj    based on some ideas from Dain Samples of UC Berkeley.
5*38fd1498Szrj    Further mangling by Bob Manson, Cygnus Support.
6*38fd1498Szrj    Further mangled by Nathan Sidwell, CodeSourcery
7*38fd1498Szrj 
8*38fd1498Szrj This file is part of GCC.
9*38fd1498Szrj 
10*38fd1498Szrj GCC is free software; you can redistribute it and/or modify it under
11*38fd1498Szrj the terms of the GNU General Public License as published by the Free
12*38fd1498Szrj Software Foundation; either version 3, or (at your option) any later
13*38fd1498Szrj version.
14*38fd1498Szrj 
15*38fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT ANY
16*38fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or
17*38fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
18*38fd1498Szrj for more details.
19*38fd1498Szrj 
20*38fd1498Szrj You should have received a copy of the GNU General Public License
21*38fd1498Szrj along with GCC; see the file COPYING3.  If not see
22*38fd1498Szrj <http://www.gnu.org/licenses/>.  */
23*38fd1498Szrj 
24*38fd1498Szrj 
25*38fd1498Szrj #define GCOV_LINKAGE
26*38fd1498Szrj 
27*38fd1498Szrj #include "config.h"
28*38fd1498Szrj #include "system.h"
29*38fd1498Szrj #include "coretypes.h"
30*38fd1498Szrj #include "backend.h"
31*38fd1498Szrj #include "target.h"
32*38fd1498Szrj #include "rtl.h"
33*38fd1498Szrj #include "tree.h"
34*38fd1498Szrj #include "tree-pass.h"
35*38fd1498Szrj #include "memmodel.h"
36*38fd1498Szrj #include "tm_p.h"
37*38fd1498Szrj #include "stringpool.h"
38*38fd1498Szrj #include "cgraph.h"
39*38fd1498Szrj #include "coverage.h"
40*38fd1498Szrj #include "diagnostic-core.h"
41*38fd1498Szrj #include "fold-const.h"
42*38fd1498Szrj #include "stor-layout.h"
43*38fd1498Szrj #include "output.h"
44*38fd1498Szrj #include "toplev.h"
45*38fd1498Szrj #include "langhooks.h"
46*38fd1498Szrj #include "tree-iterator.h"
47*38fd1498Szrj #include "context.h"
48*38fd1498Szrj #include "pass_manager.h"
49*38fd1498Szrj #include "intl.h"
50*38fd1498Szrj #include "params.h"
51*38fd1498Szrj #include "auto-profile.h"
52*38fd1498Szrj 
53*38fd1498Szrj #include "gcov-io.c"
54*38fd1498Szrj 
55*38fd1498Szrj struct GTY((chain_next ("%h.next"))) coverage_data
56*38fd1498Szrj {
57*38fd1498Szrj   struct coverage_data *next;	 /* next function */
58*38fd1498Szrj   unsigned ident;		 /* function ident */
59*38fd1498Szrj   unsigned lineno_checksum;	 /* function lineno checksum */
60*38fd1498Szrj   unsigned cfg_checksum;	 /* function cfg checksum */
61*38fd1498Szrj   tree fn_decl;			 /* the function decl */
62*38fd1498Szrj   tree ctr_vars[GCOV_COUNTERS];	 /* counter variables.  */
63*38fd1498Szrj };
64*38fd1498Szrj 
65*38fd1498Szrj /* Counts information for a function.  */
66*38fd1498Szrj struct counts_entry : pointer_hash <counts_entry>
67*38fd1498Szrj {
68*38fd1498Szrj   /* We hash by  */
69*38fd1498Szrj   unsigned ident;
70*38fd1498Szrj   unsigned ctr;
71*38fd1498Szrj 
72*38fd1498Szrj   /* Store  */
73*38fd1498Szrj   unsigned lineno_checksum;
74*38fd1498Szrj   unsigned cfg_checksum;
75*38fd1498Szrj   gcov_type *counts;
76*38fd1498Szrj   struct gcov_ctr_summary summary;
77*38fd1498Szrj 
78*38fd1498Szrj   /* hash_table support.  */
79*38fd1498Szrj   static inline hashval_t hash (const counts_entry *);
80*38fd1498Szrj   static int equal (const counts_entry *, const counts_entry *);
81*38fd1498Szrj   static void remove (counts_entry *);
82*38fd1498Szrj };
83*38fd1498Szrj 
84*38fd1498Szrj static GTY(()) struct coverage_data *functions_head = 0;
85*38fd1498Szrj static struct coverage_data **functions_tail = &functions_head;
86*38fd1498Szrj static unsigned no_coverage = 0;
87*38fd1498Szrj 
88*38fd1498Szrj /* Cumulative counter information for whole program.  */
89*38fd1498Szrj static unsigned prg_ctr_mask; /* Mask of counter types generated.  */
90*38fd1498Szrj 
91*38fd1498Szrj /* Counter information for current function.  */
92*38fd1498Szrj static unsigned fn_ctr_mask; /* Mask of counters used.  */
93*38fd1498Szrj static GTY(()) tree fn_v_ctrs[GCOV_COUNTERS];   /* counter variables.  */
94*38fd1498Szrj static unsigned fn_n_ctrs[GCOV_COUNTERS]; /* Counters allocated.  */
95*38fd1498Szrj static unsigned fn_b_ctrs[GCOV_COUNTERS]; /* Allocation base.  */
96*38fd1498Szrj 
97*38fd1498Szrj /* Coverage info VAR_DECL and function info type nodes.  */
98*38fd1498Szrj static GTY(()) tree gcov_info_var;
99*38fd1498Szrj static GTY(()) tree gcov_fn_info_type;
100*38fd1498Szrj static GTY(()) tree gcov_fn_info_ptr_type;
101*38fd1498Szrj 
102*38fd1498Szrj /* Name of the notes (gcno) output file.  The "bbg" prefix is for
103*38fd1498Szrj    historical reasons, when the notes file contained only the
104*38fd1498Szrj    basic block graph notes.
105*38fd1498Szrj    If this is NULL we're not writing to the notes file.  */
106*38fd1498Szrj static char *bbg_file_name;
107*38fd1498Szrj 
108*38fd1498Szrj /* File stamp for notes file.  */
109*38fd1498Szrj static unsigned bbg_file_stamp;
110*38fd1498Szrj 
111*38fd1498Szrj /* Name of the count data (gcda) file.  */
112*38fd1498Szrj static char *da_file_name;
113*38fd1498Szrj 
114*38fd1498Szrj /* The names of merge functions for counters.  */
115*38fd1498Szrj #define STR(str) #str
116*38fd1498Szrj #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) STR(__gcov_merge ## FN_TYPE),
117*38fd1498Szrj static const char *const ctr_merge_functions[GCOV_COUNTERS] = {
118*38fd1498Szrj #include "gcov-counter.def"
119*38fd1498Szrj };
120*38fd1498Szrj #undef DEF_GCOV_COUNTER
121*38fd1498Szrj #undef STR
122*38fd1498Szrj 
123*38fd1498Szrj #define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) NAME,
124*38fd1498Szrj static const char *const ctr_names[GCOV_COUNTERS] = {
125*38fd1498Szrj #include "gcov-counter.def"
126*38fd1498Szrj };
127*38fd1498Szrj #undef DEF_GCOV_COUNTER
128*38fd1498Szrj 
129*38fd1498Szrj /* Forward declarations.  */
130*38fd1498Szrj static void read_counts_file (void);
131*38fd1498Szrj static tree build_var (tree, tree, int);
132*38fd1498Szrj static void build_fn_info_type (tree, unsigned, tree);
133*38fd1498Szrj static void build_info_type (tree, tree);
134*38fd1498Szrj static tree build_fn_info (const struct coverage_data *, tree, tree);
135*38fd1498Szrj static tree build_info (tree, tree);
136*38fd1498Szrj static bool coverage_obj_init (void);
137*38fd1498Szrj static vec<constructor_elt, va_gc> *coverage_obj_fn
138*38fd1498Szrj (vec<constructor_elt, va_gc> *, tree, struct coverage_data const *);
139*38fd1498Szrj static void coverage_obj_finish (vec<constructor_elt, va_gc> *);
140*38fd1498Szrj 
141*38fd1498Szrj /* Return the type node for gcov_type.  */
142*38fd1498Szrj 
143*38fd1498Szrj tree
144*38fd1498Szrj get_gcov_type (void)
145*38fd1498Szrj {
146*38fd1498Szrj   scalar_int_mode mode
147*38fd1498Szrj     = smallest_int_mode_for_size (LONG_LONG_TYPE_SIZE > 32 ? 64 : 32);
148*38fd1498Szrj   return lang_hooks.types.type_for_mode (mode, false);
149*38fd1498Szrj }
150*38fd1498Szrj 
151*38fd1498Szrj /* Return the type node for gcov_unsigned_t.  */
152*38fd1498Szrj 
153*38fd1498Szrj static tree
154*38fd1498Szrj get_gcov_unsigned_t (void)
155*38fd1498Szrj {
156*38fd1498Szrj   scalar_int_mode mode = smallest_int_mode_for_size (32);
157*38fd1498Szrj   return lang_hooks.types.type_for_mode (mode, true);
158*38fd1498Szrj }
159*38fd1498Szrj 
160*38fd1498Szrj inline hashval_t
161*38fd1498Szrj counts_entry::hash (const counts_entry *entry)
162*38fd1498Szrj {
163*38fd1498Szrj   return entry->ident * GCOV_COUNTERS + entry->ctr;
164*38fd1498Szrj }
165*38fd1498Szrj 
166*38fd1498Szrj inline int
167*38fd1498Szrj counts_entry::equal (const counts_entry *entry1, const counts_entry *entry2)
168*38fd1498Szrj {
169*38fd1498Szrj   return entry1->ident == entry2->ident && entry1->ctr == entry2->ctr;
170*38fd1498Szrj }
171*38fd1498Szrj 
172*38fd1498Szrj inline void
173*38fd1498Szrj counts_entry::remove (counts_entry *entry)
174*38fd1498Szrj {
175*38fd1498Szrj   free (entry->counts);
176*38fd1498Szrj   free (entry);
177*38fd1498Szrj }
178*38fd1498Szrj 
179*38fd1498Szrj /* Hash table of count data.  */
180*38fd1498Szrj static hash_table<counts_entry> *counts_hash;
181*38fd1498Szrj 
182*38fd1498Szrj /* Read in the counts file, if available.  */
183*38fd1498Szrj 
184*38fd1498Szrj static void
185*38fd1498Szrj read_counts_file (void)
186*38fd1498Szrj {
187*38fd1498Szrj   gcov_unsigned_t fn_ident = 0;
188*38fd1498Szrj   struct gcov_summary summary;
189*38fd1498Szrj   unsigned new_summary = 1;
190*38fd1498Szrj   gcov_unsigned_t tag;
191*38fd1498Szrj   int is_error = 0;
192*38fd1498Szrj   unsigned lineno_checksum = 0;
193*38fd1498Szrj   unsigned cfg_checksum = 0;
194*38fd1498Szrj 
195*38fd1498Szrj   if (!gcov_open (da_file_name, 1))
196*38fd1498Szrj     return;
197*38fd1498Szrj 
198*38fd1498Szrj   if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
199*38fd1498Szrj     {
200*38fd1498Szrj       warning (0, "%qs is not a gcov data file", da_file_name);
201*38fd1498Szrj       gcov_close ();
202*38fd1498Szrj       return;
203*38fd1498Szrj     }
204*38fd1498Szrj   else if ((tag = gcov_read_unsigned ()) != GCOV_VERSION)
205*38fd1498Szrj     {
206*38fd1498Szrj       char v[4], e[4];
207*38fd1498Szrj 
208*38fd1498Szrj       GCOV_UNSIGNED2STRING (v, tag);
209*38fd1498Szrj       GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
210*38fd1498Szrj 
211*38fd1498Szrj       warning (0, "%qs is version %q.*s, expected version %q.*s",
212*38fd1498Szrj  	       da_file_name, 4, v, 4, e);
213*38fd1498Szrj       gcov_close ();
214*38fd1498Szrj       return;
215*38fd1498Szrj     }
216*38fd1498Szrj 
217*38fd1498Szrj   /* Read the stamp, used for creating a generation count.  */
218*38fd1498Szrj   tag = gcov_read_unsigned ();
219*38fd1498Szrj   bbg_file_stamp = crc32_unsigned (bbg_file_stamp, tag);
220*38fd1498Szrj 
221*38fd1498Szrj   counts_hash = new hash_table<counts_entry> (10);
222*38fd1498Szrj   while ((tag = gcov_read_unsigned ()))
223*38fd1498Szrj     {
224*38fd1498Szrj       gcov_unsigned_t length;
225*38fd1498Szrj       gcov_position_t offset;
226*38fd1498Szrj 
227*38fd1498Szrj       length = gcov_read_unsigned ();
228*38fd1498Szrj       offset = gcov_position ();
229*38fd1498Szrj       if (tag == GCOV_TAG_FUNCTION)
230*38fd1498Szrj 	{
231*38fd1498Szrj 	  if (length)
232*38fd1498Szrj 	    {
233*38fd1498Szrj 	      fn_ident = gcov_read_unsigned ();
234*38fd1498Szrj 	      lineno_checksum = gcov_read_unsigned ();
235*38fd1498Szrj 	      cfg_checksum = gcov_read_unsigned ();
236*38fd1498Szrj 	    }
237*38fd1498Szrj 	  else
238*38fd1498Szrj 	    fn_ident = lineno_checksum = cfg_checksum = 0;
239*38fd1498Szrj 	  new_summary = 1;
240*38fd1498Szrj 	}
241*38fd1498Szrj       else if (tag == GCOV_TAG_PROGRAM_SUMMARY)
242*38fd1498Szrj 	{
243*38fd1498Szrj 	  struct gcov_summary sum;
244*38fd1498Szrj 	  unsigned ix;
245*38fd1498Szrj 
246*38fd1498Szrj 	  if (new_summary)
247*38fd1498Szrj 	    memset (&summary, 0, sizeof (summary));
248*38fd1498Szrj 
249*38fd1498Szrj 	  gcov_read_summary (&sum);
250*38fd1498Szrj 	  for (ix = 0; ix != GCOV_COUNTERS_SUMMABLE; ix++)
251*38fd1498Szrj 	    {
252*38fd1498Szrj 	      summary.ctrs[ix].runs += sum.ctrs[ix].runs;
253*38fd1498Szrj 	      summary.ctrs[ix].sum_all += sum.ctrs[ix].sum_all;
254*38fd1498Szrj 	      if (summary.ctrs[ix].run_max < sum.ctrs[ix].run_max)
255*38fd1498Szrj 		summary.ctrs[ix].run_max = sum.ctrs[ix].run_max;
256*38fd1498Szrj 	      summary.ctrs[ix].sum_max += sum.ctrs[ix].sum_max;
257*38fd1498Szrj 	    }
258*38fd1498Szrj           if (new_summary)
259*38fd1498Szrj             memcpy (summary.ctrs[GCOV_COUNTER_ARCS].histogram,
260*38fd1498Szrj                     sum.ctrs[GCOV_COUNTER_ARCS].histogram,
261*38fd1498Szrj                     sizeof (gcov_bucket_type) * GCOV_HISTOGRAM_SIZE);
262*38fd1498Szrj           else
263*38fd1498Szrj             gcov_histogram_merge (summary.ctrs[GCOV_COUNTER_ARCS].histogram,
264*38fd1498Szrj                                   sum.ctrs[GCOV_COUNTER_ARCS].histogram);
265*38fd1498Szrj 	  new_summary = 0;
266*38fd1498Szrj 	}
267*38fd1498Szrj       else if (GCOV_TAG_IS_COUNTER (tag) && fn_ident)
268*38fd1498Szrj 	{
269*38fd1498Szrj 	  counts_entry **slot, *entry, elt;
270*38fd1498Szrj 	  unsigned n_counts = GCOV_TAG_COUNTER_NUM (length);
271*38fd1498Szrj 	  unsigned ix;
272*38fd1498Szrj 
273*38fd1498Szrj 	  elt.ident = fn_ident;
274*38fd1498Szrj 	  elt.ctr = GCOV_COUNTER_FOR_TAG (tag);
275*38fd1498Szrj 
276*38fd1498Szrj 	  slot = counts_hash->find_slot (&elt, INSERT);
277*38fd1498Szrj 	  entry = *slot;
278*38fd1498Szrj 	  if (!entry)
279*38fd1498Szrj 	    {
280*38fd1498Szrj 	      *slot = entry = XCNEW (counts_entry);
281*38fd1498Szrj 	      entry->ident = fn_ident;
282*38fd1498Szrj 	      entry->ctr = elt.ctr;
283*38fd1498Szrj 	      entry->lineno_checksum = lineno_checksum;
284*38fd1498Szrj 	      entry->cfg_checksum = cfg_checksum;
285*38fd1498Szrj               if (elt.ctr < GCOV_COUNTERS_SUMMABLE)
286*38fd1498Szrj                 entry->summary = summary.ctrs[elt.ctr];
287*38fd1498Szrj               entry->summary.num = n_counts;
288*38fd1498Szrj 	      entry->counts = XCNEWVEC (gcov_type, n_counts);
289*38fd1498Szrj 	    }
290*38fd1498Szrj 	  else if (entry->lineno_checksum != lineno_checksum
291*38fd1498Szrj 		   || entry->cfg_checksum != cfg_checksum)
292*38fd1498Szrj 	    {
293*38fd1498Szrj 	      error ("Profile data for function %u is corrupted", fn_ident);
294*38fd1498Szrj 	      error ("checksum is (%x,%x) instead of (%x,%x)",
295*38fd1498Szrj 		     entry->lineno_checksum, entry->cfg_checksum,
296*38fd1498Szrj 		     lineno_checksum, cfg_checksum);
297*38fd1498Szrj 	      delete counts_hash;
298*38fd1498Szrj 	      counts_hash = NULL;
299*38fd1498Szrj 	      break;
300*38fd1498Szrj 	    }
301*38fd1498Szrj 	  else if (entry->summary.num != n_counts)
302*38fd1498Szrj 	    {
303*38fd1498Szrj 	      error ("Profile data for function %u is corrupted", fn_ident);
304*38fd1498Szrj 	      error ("number of counters is %d instead of %d", entry->summary.num, n_counts);
305*38fd1498Szrj 	      delete counts_hash;
306*38fd1498Szrj 	      counts_hash = NULL;
307*38fd1498Szrj 	      break;
308*38fd1498Szrj 	    }
309*38fd1498Szrj 	  else if (elt.ctr >= GCOV_COUNTERS_SUMMABLE)
310*38fd1498Szrj 	    {
311*38fd1498Szrj 	      error ("cannot merge separate %s counters for function %u",
312*38fd1498Szrj 		     ctr_names[elt.ctr], fn_ident);
313*38fd1498Szrj 	      goto skip_merge;
314*38fd1498Szrj 	    }
315*38fd1498Szrj 	  else
316*38fd1498Szrj 	    {
317*38fd1498Szrj 	      entry->summary.runs += summary.ctrs[elt.ctr].runs;
318*38fd1498Szrj 	      entry->summary.sum_all += summary.ctrs[elt.ctr].sum_all;
319*38fd1498Szrj 	      if (entry->summary.run_max < summary.ctrs[elt.ctr].run_max)
320*38fd1498Szrj 		entry->summary.run_max = summary.ctrs[elt.ctr].run_max;
321*38fd1498Szrj 	      entry->summary.sum_max += summary.ctrs[elt.ctr].sum_max;
322*38fd1498Szrj 	    }
323*38fd1498Szrj 	  for (ix = 0; ix != n_counts; ix++)
324*38fd1498Szrj 	    entry->counts[ix] += gcov_read_counter ();
325*38fd1498Szrj 	skip_merge:;
326*38fd1498Szrj 	}
327*38fd1498Szrj       gcov_sync (offset, length);
328*38fd1498Szrj       if ((is_error = gcov_is_error ()))
329*38fd1498Szrj 	{
330*38fd1498Szrj 	  error (is_error < 0
331*38fd1498Szrj 		 ? G_("%qs has overflowed")
332*38fd1498Szrj 		 : G_("%qs is corrupted"),
333*38fd1498Szrj 		 da_file_name);
334*38fd1498Szrj 	  delete counts_hash;
335*38fd1498Szrj 	  counts_hash = NULL;
336*38fd1498Szrj 	  break;
337*38fd1498Szrj 	}
338*38fd1498Szrj     }
339*38fd1498Szrj 
340*38fd1498Szrj   gcov_close ();
341*38fd1498Szrj }
342*38fd1498Szrj 
343*38fd1498Szrj /* Returns the counters for a particular tag.  */
344*38fd1498Szrj 
345*38fd1498Szrj gcov_type *
346*38fd1498Szrj get_coverage_counts (unsigned counter, unsigned expected,
347*38fd1498Szrj                      unsigned cfg_checksum, unsigned lineno_checksum,
348*38fd1498Szrj 		     const struct gcov_ctr_summary **summary)
349*38fd1498Szrj {
350*38fd1498Szrj   counts_entry *entry, elt;
351*38fd1498Szrj 
352*38fd1498Szrj   /* No hash table, no counts.  */
353*38fd1498Szrj   if (!counts_hash)
354*38fd1498Szrj     {
355*38fd1498Szrj       static int warned = 0;
356*38fd1498Szrj 
357*38fd1498Szrj       if (!warned++ && dump_enabled_p ())
358*38fd1498Szrj 	dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, input_location,
359*38fd1498Szrj                          (flag_guess_branch_prob
360*38fd1498Szrj                           ? "file %s not found, execution counts estimated\n"
361*38fd1498Szrj                           : "file %s not found, execution counts assumed to "
362*38fd1498Szrj                             "be zero\n"),
363*38fd1498Szrj                          da_file_name);
364*38fd1498Szrj       return NULL;
365*38fd1498Szrj     }
366*38fd1498Szrj   if (PARAM_VALUE (PARAM_PROFILE_FUNC_INTERNAL_ID))
367*38fd1498Szrj     elt.ident = current_function_funcdef_no + 1;
368*38fd1498Szrj   else
369*38fd1498Szrj     {
370*38fd1498Szrj       gcc_assert (coverage_node_map_initialized_p ());
371*38fd1498Szrj       elt.ident = cgraph_node::get (cfun->decl)->profile_id;
372*38fd1498Szrj     }
373*38fd1498Szrj   elt.ctr = counter;
374*38fd1498Szrj   entry = counts_hash->find (&elt);
375*38fd1498Szrj   if (!entry || !entry->summary.num)
376*38fd1498Szrj     /* The function was not emitted, or is weak and not chosen in the
377*38fd1498Szrj        final executable.  Silently fail, because there's nothing we
378*38fd1498Szrj        can do about it.  */
379*38fd1498Szrj     return NULL;
380*38fd1498Szrj 
381*38fd1498Szrj   if (entry->cfg_checksum != cfg_checksum
382*38fd1498Szrj       || entry->summary.num != expected)
383*38fd1498Szrj     {
384*38fd1498Szrj       static int warned = 0;
385*38fd1498Szrj       bool warning_printed = false;
386*38fd1498Szrj       tree id = DECL_ASSEMBLER_NAME (current_function_decl);
387*38fd1498Szrj 
388*38fd1498Szrj       warning_printed =
389*38fd1498Szrj 	warning_at (input_location, OPT_Wcoverage_mismatch,
390*38fd1498Szrj 		    "the control flow of function %qE does not match "
391*38fd1498Szrj 		    "its profile data (counter %qs)", id, ctr_names[counter]);
392*38fd1498Szrj       if (warning_printed && dump_enabled_p ())
393*38fd1498Szrj 	{
394*38fd1498Szrj           dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, input_location,
395*38fd1498Szrj                            "use -Wno-error=coverage-mismatch to tolerate "
396*38fd1498Szrj                            "the mismatch but performance may drop if the "
397*38fd1498Szrj                            "function is hot\n");
398*38fd1498Szrj 
399*38fd1498Szrj 	  if (!seen_error ()
400*38fd1498Szrj 	      && !warned++)
401*38fd1498Szrj 	    {
402*38fd1498Szrj 	      dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, input_location,
403*38fd1498Szrj                                "coverage mismatch ignored\n");
404*38fd1498Szrj 	      dump_printf (MSG_OPTIMIZED_LOCATIONS,
405*38fd1498Szrj                            flag_guess_branch_prob
406*38fd1498Szrj                            ? G_("execution counts estimated\n")
407*38fd1498Szrj                            : G_("execution counts assumed to be zero\n"));
408*38fd1498Szrj 	      if (!flag_guess_branch_prob)
409*38fd1498Szrj 		dump_printf (MSG_OPTIMIZED_LOCATIONS,
410*38fd1498Szrj                              "this can result in poorly optimized code\n");
411*38fd1498Szrj 	    }
412*38fd1498Szrj 	}
413*38fd1498Szrj 
414*38fd1498Szrj       return NULL;
415*38fd1498Szrj     }
416*38fd1498Szrj   else if (entry->lineno_checksum != lineno_checksum)
417*38fd1498Szrj     {
418*38fd1498Szrj       warning (OPT_Wcoverage_mismatch,
419*38fd1498Szrj                "source locations for function %qE have changed,"
420*38fd1498Szrj 	       " the profile data may be out of date",
421*38fd1498Szrj 	       DECL_ASSEMBLER_NAME (current_function_decl));
422*38fd1498Szrj     }
423*38fd1498Szrj 
424*38fd1498Szrj   if (summary)
425*38fd1498Szrj     *summary = &entry->summary;
426*38fd1498Szrj 
427*38fd1498Szrj   return entry->counts;
428*38fd1498Szrj }
429*38fd1498Szrj 
430*38fd1498Szrj /* Allocate NUM counters of type COUNTER. Returns nonzero if the
431*38fd1498Szrj    allocation succeeded.  */
432*38fd1498Szrj 
433*38fd1498Szrj int
434*38fd1498Szrj coverage_counter_alloc (unsigned counter, unsigned num)
435*38fd1498Szrj {
436*38fd1498Szrj   if (no_coverage)
437*38fd1498Szrj     return 0;
438*38fd1498Szrj 
439*38fd1498Szrj   if (!num)
440*38fd1498Szrj     return 1;
441*38fd1498Szrj 
442*38fd1498Szrj   if (!fn_v_ctrs[counter])
443*38fd1498Szrj     {
444*38fd1498Szrj       tree array_type = build_array_type (get_gcov_type (), NULL_TREE);
445*38fd1498Szrj 
446*38fd1498Szrj       fn_v_ctrs[counter]
447*38fd1498Szrj 	= build_var (current_function_decl, array_type, counter);
448*38fd1498Szrj     }
449*38fd1498Szrj 
450*38fd1498Szrj   fn_b_ctrs[counter] = fn_n_ctrs[counter];
451*38fd1498Szrj   fn_n_ctrs[counter] += num;
452*38fd1498Szrj 
453*38fd1498Szrj   fn_ctr_mask |= 1 << counter;
454*38fd1498Szrj   return 1;
455*38fd1498Szrj }
456*38fd1498Szrj 
457*38fd1498Szrj /* Generate a tree to access COUNTER NO.  */
458*38fd1498Szrj 
459*38fd1498Szrj tree
460*38fd1498Szrj tree_coverage_counter_ref (unsigned counter, unsigned no)
461*38fd1498Szrj {
462*38fd1498Szrj   tree gcov_type_node = get_gcov_type ();
463*38fd1498Szrj 
464*38fd1498Szrj   gcc_assert (no < fn_n_ctrs[counter] - fn_b_ctrs[counter]);
465*38fd1498Szrj 
466*38fd1498Szrj   no += fn_b_ctrs[counter];
467*38fd1498Szrj 
468*38fd1498Szrj   /* "no" here is an array index, scaled to bytes later.  */
469*38fd1498Szrj   return build4 (ARRAY_REF, gcov_type_node, fn_v_ctrs[counter],
470*38fd1498Szrj 		 build_int_cst (integer_type_node, no), NULL, NULL);
471*38fd1498Szrj }
472*38fd1498Szrj 
473*38fd1498Szrj /* Generate a tree to access the address of COUNTER NO.  */
474*38fd1498Szrj 
475*38fd1498Szrj tree
476*38fd1498Szrj tree_coverage_counter_addr (unsigned counter, unsigned no)
477*38fd1498Szrj {
478*38fd1498Szrj   tree gcov_type_node = get_gcov_type ();
479*38fd1498Szrj 
480*38fd1498Szrj   gcc_assert (no < fn_n_ctrs[counter] - fn_b_ctrs[counter]);
481*38fd1498Szrj   no += fn_b_ctrs[counter];
482*38fd1498Szrj 
483*38fd1498Szrj   /* "no" here is an array index, scaled to bytes later.  */
484*38fd1498Szrj   return build_fold_addr_expr (build4 (ARRAY_REF, gcov_type_node,
485*38fd1498Szrj 				       fn_v_ctrs[counter],
486*38fd1498Szrj 				       build_int_cst (integer_type_node, no),
487*38fd1498Szrj 				       NULL, NULL));
488*38fd1498Szrj }
489*38fd1498Szrj 
490*38fd1498Szrj 
491*38fd1498Szrj /* Generate a checksum for a string.  CHKSUM is the current
492*38fd1498Szrj    checksum.  */
493*38fd1498Szrj 
494*38fd1498Szrj static unsigned
495*38fd1498Szrj coverage_checksum_string (unsigned chksum, const char *string)
496*38fd1498Szrj {
497*38fd1498Szrj   int i;
498*38fd1498Szrj   char *dup = NULL;
499*38fd1498Szrj 
500*38fd1498Szrj   /* Look for everything that looks if it were produced by
501*38fd1498Szrj      get_file_function_name and zero out the second part
502*38fd1498Szrj      that may result from flag_random_seed.  This is not critical
503*38fd1498Szrj      as the checksums are used only for sanity checking.  */
504*38fd1498Szrj   for (i = 0; string[i]; i++)
505*38fd1498Szrj     {
506*38fd1498Szrj       int offset = 0;
507*38fd1498Szrj       if (!strncmp (string + i, "_GLOBAL__N_", 11))
508*38fd1498Szrj       offset = 11;
509*38fd1498Szrj       if (!strncmp (string + i, "_GLOBAL__", 9))
510*38fd1498Szrj       offset = 9;
511*38fd1498Szrj 
512*38fd1498Szrj       /* C++ namespaces do have scheme:
513*38fd1498Szrj          _GLOBAL__N_<filename>_<wrongmagicnumber>_<magicnumber>functionname
514*38fd1498Szrj        since filename might contain extra underscores there seems
515*38fd1498Szrj        to be no better chance then walk all possible offsets looking
516*38fd1498Szrj        for magicnumber.  */
517*38fd1498Szrj       if (offset)
518*38fd1498Szrj 	{
519*38fd1498Szrj 	  for (i = i + offset; string[i]; i++)
520*38fd1498Szrj 	    if (string[i]=='_')
521*38fd1498Szrj 	      {
522*38fd1498Szrj 		int y;
523*38fd1498Szrj 
524*38fd1498Szrj 		for (y = 1; y < 9; y++)
525*38fd1498Szrj 		  if (!(string[i + y] >= '0' && string[i + y] <= '9')
526*38fd1498Szrj 		      && !(string[i + y] >= 'A' && string[i + y] <= 'F'))
527*38fd1498Szrj 		    break;
528*38fd1498Szrj 		if (y != 9 || string[i + 9] != '_')
529*38fd1498Szrj 		  continue;
530*38fd1498Szrj 		for (y = 10; y < 18; y++)
531*38fd1498Szrj 		  if (!(string[i + y] >= '0' && string[i + y] <= '9')
532*38fd1498Szrj 		      && !(string[i + y] >= 'A' && string[i + y] <= 'F'))
533*38fd1498Szrj 		    break;
534*38fd1498Szrj 		if (y != 18)
535*38fd1498Szrj 		  continue;
536*38fd1498Szrj 		if (!dup)
537*38fd1498Szrj 		  string = dup = xstrdup (string);
538*38fd1498Szrj 		for (y = 10; y < 18; y++)
539*38fd1498Szrj 		  dup[i + y] = '0';
540*38fd1498Szrj 	      }
541*38fd1498Szrj 	  break;
542*38fd1498Szrj 	}
543*38fd1498Szrj     }
544*38fd1498Szrj 
545*38fd1498Szrj   chksum = crc32_string (chksum, string);
546*38fd1498Szrj   free (dup);
547*38fd1498Szrj 
548*38fd1498Szrj   return chksum;
549*38fd1498Szrj }
550*38fd1498Szrj 
551*38fd1498Szrj /* Compute checksum for the current function.  We generate a CRC32.  */
552*38fd1498Szrj 
553*38fd1498Szrj unsigned
554*38fd1498Szrj coverage_compute_lineno_checksum (void)
555*38fd1498Szrj {
556*38fd1498Szrj   expanded_location xloc
557*38fd1498Szrj     = expand_location (DECL_SOURCE_LOCATION (current_function_decl));
558*38fd1498Szrj   unsigned chksum = xloc.line;
559*38fd1498Szrj 
560*38fd1498Szrj   if (xloc.file)
561*38fd1498Szrj     chksum = coverage_checksum_string (chksum, xloc.file);
562*38fd1498Szrj   chksum = coverage_checksum_string
563*38fd1498Szrj     (chksum, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl)));
564*38fd1498Szrj 
565*38fd1498Szrj   return chksum;
566*38fd1498Szrj }
567*38fd1498Szrj 
568*38fd1498Szrj /* Compute profile ID.  This is better to be unique in whole program.  */
569*38fd1498Szrj 
570*38fd1498Szrj unsigned
571*38fd1498Szrj coverage_compute_profile_id (struct cgraph_node *n)
572*38fd1498Szrj {
573*38fd1498Szrj   unsigned chksum;
574*38fd1498Szrj 
575*38fd1498Szrj   /* Externally visible symbols have unique name.  */
576*38fd1498Szrj   if (TREE_PUBLIC (n->decl) || DECL_EXTERNAL (n->decl) || n->unique_name)
577*38fd1498Szrj     {
578*38fd1498Szrj       chksum = coverage_checksum_string
579*38fd1498Szrj 	(0, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (n->decl)));
580*38fd1498Szrj     }
581*38fd1498Szrj   else
582*38fd1498Szrj     {
583*38fd1498Szrj       expanded_location xloc
584*38fd1498Szrj 	= expand_location (DECL_SOURCE_LOCATION (n->decl));
585*38fd1498Szrj       bool use_name_only = (PARAM_VALUE (PARAM_PROFILE_FUNC_INTERNAL_ID) == 0);
586*38fd1498Szrj 
587*38fd1498Szrj       chksum = (use_name_only ? 0 : xloc.line);
588*38fd1498Szrj       if (xloc.file)
589*38fd1498Szrj 	chksum = coverage_checksum_string (chksum, xloc.file);
590*38fd1498Szrj       chksum = coverage_checksum_string
591*38fd1498Szrj 	(chksum, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (n->decl)));
592*38fd1498Szrj       if (!use_name_only && first_global_object_name)
593*38fd1498Szrj 	chksum = coverage_checksum_string
594*38fd1498Szrj 	  (chksum, first_global_object_name);
595*38fd1498Szrj       chksum = coverage_checksum_string
596*38fd1498Szrj 	(chksum, aux_base_name);
597*38fd1498Szrj     }
598*38fd1498Szrj 
599*38fd1498Szrj   /* Non-negative integers are hopefully small enough to fit in all targets.
600*38fd1498Szrj      Gcov file formats wants non-zero function IDs.  */
601*38fd1498Szrj   chksum = chksum & 0x7fffffff;
602*38fd1498Szrj   return chksum + (!chksum);
603*38fd1498Szrj }
604*38fd1498Szrj 
605*38fd1498Szrj /* Compute cfg checksum for the function FN given as argument.
606*38fd1498Szrj    The checksum is calculated carefully so that
607*38fd1498Szrj    source code changes that doesn't affect the control flow graph
608*38fd1498Szrj    won't change the checksum.
609*38fd1498Szrj    This is to make the profile data useable across source code change.
610*38fd1498Szrj    The downside of this is that the compiler may use potentially
611*38fd1498Szrj    wrong profile data - that the source code change has non-trivial impact
612*38fd1498Szrj    on the validity of profile data (e.g. the reversed condition)
613*38fd1498Szrj    but the compiler won't detect the change and use the wrong profile data.  */
614*38fd1498Szrj 
615*38fd1498Szrj unsigned
616*38fd1498Szrj coverage_compute_cfg_checksum (struct function *fn)
617*38fd1498Szrj {
618*38fd1498Szrj   basic_block bb;
619*38fd1498Szrj   unsigned chksum = n_basic_blocks_for_fn (fn);
620*38fd1498Szrj 
621*38fd1498Szrj   FOR_EACH_BB_FN (bb, fn)
622*38fd1498Szrj     {
623*38fd1498Szrj       edge e;
624*38fd1498Szrj       edge_iterator ei;
625*38fd1498Szrj       chksum = crc32_byte (chksum, bb->index);
626*38fd1498Szrj       FOR_EACH_EDGE (e, ei, bb->succs)
627*38fd1498Szrj         {
628*38fd1498Szrj           chksum = crc32_byte (chksum, e->dest->index);
629*38fd1498Szrj         }
630*38fd1498Szrj     }
631*38fd1498Szrj 
632*38fd1498Szrj   return chksum;
633*38fd1498Szrj }
634*38fd1498Szrj 
635*38fd1498Szrj /* Begin output to the notes file for the current function.
636*38fd1498Szrj    Writes the function header. Returns nonzero if data should be output.  */
637*38fd1498Szrj 
638*38fd1498Szrj int
639*38fd1498Szrj coverage_begin_function (unsigned lineno_checksum, unsigned cfg_checksum)
640*38fd1498Szrj {
641*38fd1498Szrj   expanded_location xloc;
642*38fd1498Szrj   unsigned long offset;
643*38fd1498Szrj 
644*38fd1498Szrj   /* We don't need to output .gcno file unless we're under -ftest-coverage
645*38fd1498Szrj      (e.g. -fprofile-arcs/generate/use don't need .gcno to work). */
646*38fd1498Szrj   if (no_coverage || !bbg_file_name)
647*38fd1498Szrj     return 0;
648*38fd1498Szrj 
649*38fd1498Szrj   xloc = expand_location (DECL_SOURCE_LOCATION (current_function_decl));
650*38fd1498Szrj 
651*38fd1498Szrj   /* Announce function */
652*38fd1498Szrj   offset = gcov_write_tag (GCOV_TAG_FUNCTION);
653*38fd1498Szrj   if (PARAM_VALUE (PARAM_PROFILE_FUNC_INTERNAL_ID))
654*38fd1498Szrj     gcov_write_unsigned (current_function_funcdef_no + 1);
655*38fd1498Szrj   else
656*38fd1498Szrj     {
657*38fd1498Szrj       gcc_assert (coverage_node_map_initialized_p ());
658*38fd1498Szrj       gcov_write_unsigned (
659*38fd1498Szrj         cgraph_node::get (current_function_decl)->profile_id);
660*38fd1498Szrj     }
661*38fd1498Szrj 
662*38fd1498Szrj   gcov_write_unsigned (lineno_checksum);
663*38fd1498Szrj   gcov_write_unsigned (cfg_checksum);
664*38fd1498Szrj   gcov_write_string (IDENTIFIER_POINTER
665*38fd1498Szrj 		     (DECL_ASSEMBLER_NAME (current_function_decl)));
666*38fd1498Szrj   gcov_write_unsigned (DECL_ARTIFICIAL (current_function_decl));
667*38fd1498Szrj   gcov_write_filename (xloc.file);
668*38fd1498Szrj   gcov_write_unsigned (xloc.line);
669*38fd1498Szrj   gcov_write_unsigned (xloc.column);
670*38fd1498Szrj 
671*38fd1498Szrj   expanded_location endloc = expand_location (cfun->function_end_locus);
672*38fd1498Szrj 
673*38fd1498Szrj   /* Function can start in a single file and end in another one.  */
674*38fd1498Szrj   gcov_write_unsigned (endloc.file == xloc.file ? endloc.line : xloc.line);
675*38fd1498Szrj   gcov_write_length (offset);
676*38fd1498Szrj 
677*38fd1498Szrj   return !gcov_is_error ();
678*38fd1498Szrj }
679*38fd1498Szrj 
680*38fd1498Szrj /* Finish coverage data for the current function. Verify no output
681*38fd1498Szrj    error has occurred.  Save function coverage counts.  */
682*38fd1498Szrj 
683*38fd1498Szrj void
684*38fd1498Szrj coverage_end_function (unsigned lineno_checksum, unsigned cfg_checksum)
685*38fd1498Szrj {
686*38fd1498Szrj   unsigned i;
687*38fd1498Szrj 
688*38fd1498Szrj   if (bbg_file_name && gcov_is_error ())
689*38fd1498Szrj     {
690*38fd1498Szrj       warning (0, "error writing %qs", bbg_file_name);
691*38fd1498Szrj       unlink (bbg_file_name);
692*38fd1498Szrj       bbg_file_name = NULL;
693*38fd1498Szrj     }
694*38fd1498Szrj 
695*38fd1498Szrj   if (fn_ctr_mask)
696*38fd1498Szrj     {
697*38fd1498Szrj       struct coverage_data *item = 0;
698*38fd1498Szrj 
699*38fd1498Szrj       item = ggc_alloc<coverage_data> ();
700*38fd1498Szrj 
701*38fd1498Szrj       if (PARAM_VALUE (PARAM_PROFILE_FUNC_INTERNAL_ID))
702*38fd1498Szrj 	item->ident = current_function_funcdef_no + 1;
703*38fd1498Szrj       else
704*38fd1498Szrj 	{
705*38fd1498Szrj 	  gcc_assert (coverage_node_map_initialized_p ());
706*38fd1498Szrj 	  item->ident = cgraph_node::get (cfun->decl)->profile_id;
707*38fd1498Szrj 	}
708*38fd1498Szrj 
709*38fd1498Szrj       item->lineno_checksum = lineno_checksum;
710*38fd1498Szrj       item->cfg_checksum = cfg_checksum;
711*38fd1498Szrj 
712*38fd1498Szrj       item->fn_decl = current_function_decl;
713*38fd1498Szrj       item->next = 0;
714*38fd1498Szrj       *functions_tail = item;
715*38fd1498Szrj       functions_tail = &item->next;
716*38fd1498Szrj 
717*38fd1498Szrj       for (i = 0; i != GCOV_COUNTERS; i++)
718*38fd1498Szrj 	{
719*38fd1498Szrj 	  tree var = fn_v_ctrs[i];
720*38fd1498Szrj 
721*38fd1498Szrj 	  if (item)
722*38fd1498Szrj 	    item->ctr_vars[i] = var;
723*38fd1498Szrj 	  if (var)
724*38fd1498Szrj 	    {
725*38fd1498Szrj 	      tree array_type = build_index_type (size_int (fn_n_ctrs[i] - 1));
726*38fd1498Szrj 	      array_type = build_array_type (get_gcov_type (), array_type);
727*38fd1498Szrj 	      TREE_TYPE (var) = array_type;
728*38fd1498Szrj 	      DECL_SIZE (var) = TYPE_SIZE (array_type);
729*38fd1498Szrj 	      DECL_SIZE_UNIT (var) = TYPE_SIZE_UNIT (array_type);
730*38fd1498Szrj 	      varpool_node::finalize_decl (var);
731*38fd1498Szrj 	    }
732*38fd1498Szrj 
733*38fd1498Szrj 	  fn_b_ctrs[i] = fn_n_ctrs[i] = 0;
734*38fd1498Szrj 	  fn_v_ctrs[i] = NULL_TREE;
735*38fd1498Szrj 	}
736*38fd1498Szrj       prg_ctr_mask |= fn_ctr_mask;
737*38fd1498Szrj       fn_ctr_mask = 0;
738*38fd1498Szrj     }
739*38fd1498Szrj }
740*38fd1498Szrj 
741*38fd1498Szrj /* Remove coverage file if opened.  */
742*38fd1498Szrj 
743*38fd1498Szrj void
744*38fd1498Szrj coverage_remove_note_file (void)
745*38fd1498Szrj {
746*38fd1498Szrj   if (bbg_file_name)
747*38fd1498Szrj     {
748*38fd1498Szrj       gcov_close ();
749*38fd1498Szrj       unlink (bbg_file_name);
750*38fd1498Szrj     }
751*38fd1498Szrj }
752*38fd1498Szrj 
753*38fd1498Szrj /* Build a coverage variable of TYPE for function FN_DECL.  If COUNTER
754*38fd1498Szrj    >= 0 it is a counter array, otherwise it is the function structure.  */
755*38fd1498Szrj 
756*38fd1498Szrj static tree
757*38fd1498Szrj build_var (tree fn_decl, tree type, int counter)
758*38fd1498Szrj {
759*38fd1498Szrj   tree var = build_decl (BUILTINS_LOCATION, VAR_DECL, NULL_TREE, type);
760*38fd1498Szrj   const char *fn_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fn_decl));
761*38fd1498Szrj   char *buf;
762*38fd1498Szrj   size_t fn_name_len, len;
763*38fd1498Szrj 
764*38fd1498Szrj   fn_name = targetm.strip_name_encoding (fn_name);
765*38fd1498Szrj   fn_name_len = strlen (fn_name);
766*38fd1498Szrj   buf = XALLOCAVEC (char, fn_name_len + 8 + sizeof (int) * 3);
767*38fd1498Szrj 
768*38fd1498Szrj   if (counter < 0)
769*38fd1498Szrj     strcpy (buf, "__gcov__");
770*38fd1498Szrj   else
771*38fd1498Szrj     sprintf (buf, "__gcov%u_", counter);
772*38fd1498Szrj   len = strlen (buf);
773*38fd1498Szrj   buf[len - 1] = symbol_table::symbol_suffix_separator ();
774*38fd1498Szrj   memcpy (buf + len, fn_name, fn_name_len + 1);
775*38fd1498Szrj   DECL_NAME (var) = get_identifier (buf);
776*38fd1498Szrj   TREE_STATIC (var) = 1;
777*38fd1498Szrj   TREE_ADDRESSABLE (var) = 1;
778*38fd1498Szrj   DECL_NONALIASED (var) = 1;
779*38fd1498Szrj   SET_DECL_ALIGN (var, TYPE_ALIGN (type));
780*38fd1498Szrj 
781*38fd1498Szrj   return var;
782*38fd1498Szrj }
783*38fd1498Szrj 
784*38fd1498Szrj /* Creates the gcov_fn_info RECORD_TYPE.  */
785*38fd1498Szrj 
786*38fd1498Szrj static void
787*38fd1498Szrj build_fn_info_type (tree type, unsigned counters, tree gcov_info_type)
788*38fd1498Szrj {
789*38fd1498Szrj   tree ctr_info = lang_hooks.types.make_type (RECORD_TYPE);
790*38fd1498Szrj   tree field, fields;
791*38fd1498Szrj   tree array_type;
792*38fd1498Szrj 
793*38fd1498Szrj   gcc_assert (counters);
794*38fd1498Szrj 
795*38fd1498Szrj   /* ctr_info::num */
796*38fd1498Szrj   field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
797*38fd1498Szrj 		      get_gcov_unsigned_t ());
798*38fd1498Szrj   fields = field;
799*38fd1498Szrj 
800*38fd1498Szrj   /* ctr_info::values */
801*38fd1498Szrj   field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
802*38fd1498Szrj 		      build_pointer_type (get_gcov_type ()));
803*38fd1498Szrj   DECL_CHAIN (field) = fields;
804*38fd1498Szrj   fields = field;
805*38fd1498Szrj 
806*38fd1498Szrj   finish_builtin_struct (ctr_info, "__gcov_ctr_info", fields, NULL_TREE);
807*38fd1498Szrj 
808*38fd1498Szrj   /* key */
809*38fd1498Szrj   field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
810*38fd1498Szrj 		      build_pointer_type (build_qualified_type
811*38fd1498Szrj 					  (gcov_info_type, TYPE_QUAL_CONST)));
812*38fd1498Szrj   fields = field;
813*38fd1498Szrj 
814*38fd1498Szrj   /* ident */
815*38fd1498Szrj   field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
816*38fd1498Szrj 		      get_gcov_unsigned_t ());
817*38fd1498Szrj   DECL_CHAIN (field) = fields;
818*38fd1498Szrj   fields = field;
819*38fd1498Szrj 
820*38fd1498Szrj   /* lineno_checksum */
821*38fd1498Szrj   field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
822*38fd1498Szrj 		      get_gcov_unsigned_t ());
823*38fd1498Szrj   DECL_CHAIN (field) = fields;
824*38fd1498Szrj   fields = field;
825*38fd1498Szrj 
826*38fd1498Szrj   /* cfg checksum */
827*38fd1498Szrj   field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
828*38fd1498Szrj 		      get_gcov_unsigned_t ());
829*38fd1498Szrj   DECL_CHAIN (field) = fields;
830*38fd1498Szrj   fields = field;
831*38fd1498Szrj 
832*38fd1498Szrj   array_type = build_index_type (size_int (counters - 1));
833*38fd1498Szrj   array_type = build_array_type (ctr_info, array_type);
834*38fd1498Szrj 
835*38fd1498Szrj   /* counters */
836*38fd1498Szrj   field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE, array_type);
837*38fd1498Szrj   DECL_CHAIN (field) = fields;
838*38fd1498Szrj   fields = field;
839*38fd1498Szrj 
840*38fd1498Szrj   finish_builtin_struct (type, "__gcov_fn_info", fields, NULL_TREE);
841*38fd1498Szrj }
842*38fd1498Szrj 
843*38fd1498Szrj /* Returns a CONSTRUCTOR for a gcov_fn_info.  DATA is
844*38fd1498Szrj    the coverage data for the function and TYPE is the gcov_fn_info
845*38fd1498Szrj    RECORD_TYPE.  KEY is the object file key.  */
846*38fd1498Szrj 
847*38fd1498Szrj static tree
848*38fd1498Szrj build_fn_info (const struct coverage_data *data, tree type, tree key)
849*38fd1498Szrj {
850*38fd1498Szrj   tree fields = TYPE_FIELDS (type);
851*38fd1498Szrj   tree ctr_type;
852*38fd1498Szrj   unsigned ix;
853*38fd1498Szrj   vec<constructor_elt, va_gc> *v1 = NULL;
854*38fd1498Szrj   vec<constructor_elt, va_gc> *v2 = NULL;
855*38fd1498Szrj 
856*38fd1498Szrj   /* key */
857*38fd1498Szrj   CONSTRUCTOR_APPEND_ELT (v1, fields,
858*38fd1498Szrj 			  build1 (ADDR_EXPR, TREE_TYPE (fields), key));
859*38fd1498Szrj   fields = DECL_CHAIN (fields);
860*38fd1498Szrj 
861*38fd1498Szrj   /* ident */
862*38fd1498Szrj   CONSTRUCTOR_APPEND_ELT (v1, fields,
863*38fd1498Szrj 			  build_int_cstu (get_gcov_unsigned_t (),
864*38fd1498Szrj 					  data->ident));
865*38fd1498Szrj   fields = DECL_CHAIN (fields);
866*38fd1498Szrj 
867*38fd1498Szrj   /* lineno_checksum */
868*38fd1498Szrj   CONSTRUCTOR_APPEND_ELT (v1, fields,
869*38fd1498Szrj 			  build_int_cstu (get_gcov_unsigned_t (),
870*38fd1498Szrj 					  data->lineno_checksum));
871*38fd1498Szrj   fields = DECL_CHAIN (fields);
872*38fd1498Szrj 
873*38fd1498Szrj   /* cfg_checksum */
874*38fd1498Szrj   CONSTRUCTOR_APPEND_ELT (v1, fields,
875*38fd1498Szrj 			  build_int_cstu (get_gcov_unsigned_t (),
876*38fd1498Szrj 					  data->cfg_checksum));
877*38fd1498Szrj   fields = DECL_CHAIN (fields);
878*38fd1498Szrj 
879*38fd1498Szrj   /* counters */
880*38fd1498Szrj   ctr_type = TREE_TYPE (TREE_TYPE (fields));
881*38fd1498Szrj   for (ix = 0; ix != GCOV_COUNTERS; ix++)
882*38fd1498Szrj     if (prg_ctr_mask & (1 << ix))
883*38fd1498Szrj       {
884*38fd1498Szrj 	vec<constructor_elt, va_gc> *ctr = NULL;
885*38fd1498Szrj 	tree var = data->ctr_vars[ix];
886*38fd1498Szrj 	unsigned count = 0;
887*38fd1498Szrj 
888*38fd1498Szrj 	if (var)
889*38fd1498Szrj 	  count
890*38fd1498Szrj 	    = tree_to_shwi (TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (var))))
891*38fd1498Szrj 	    + 1;
892*38fd1498Szrj 
893*38fd1498Szrj 	CONSTRUCTOR_APPEND_ELT (ctr, TYPE_FIELDS (ctr_type),
894*38fd1498Szrj 				build_int_cstu (get_gcov_unsigned_t (),
895*38fd1498Szrj 						count));
896*38fd1498Szrj 
897*38fd1498Szrj 	if (var)
898*38fd1498Szrj 	  CONSTRUCTOR_APPEND_ELT (ctr, DECL_CHAIN (TYPE_FIELDS (ctr_type)),
899*38fd1498Szrj 				  build_fold_addr_expr (var));
900*38fd1498Szrj 
901*38fd1498Szrj 	CONSTRUCTOR_APPEND_ELT (v2, NULL, build_constructor (ctr_type, ctr));
902*38fd1498Szrj       }
903*38fd1498Szrj 
904*38fd1498Szrj   CONSTRUCTOR_APPEND_ELT (v1, fields,
905*38fd1498Szrj 			  build_constructor (TREE_TYPE (fields), v2));
906*38fd1498Szrj 
907*38fd1498Szrj   return build_constructor (type, v1);
908*38fd1498Szrj }
909*38fd1498Szrj 
910*38fd1498Szrj /* Create gcov_info struct.  TYPE is the incomplete RECORD_TYPE to be
911*38fd1498Szrj    completed, and FN_INFO_PTR_TYPE is a pointer to the function info type.  */
912*38fd1498Szrj 
913*38fd1498Szrj static void
914*38fd1498Szrj build_info_type (tree type, tree fn_info_ptr_type)
915*38fd1498Szrj {
916*38fd1498Szrj   tree field, fields = NULL_TREE;
917*38fd1498Szrj   tree merge_fn_type;
918*38fd1498Szrj 
919*38fd1498Szrj   /* Version ident */
920*38fd1498Szrj   field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
921*38fd1498Szrj 		      get_gcov_unsigned_t ());
922*38fd1498Szrj   DECL_CHAIN (field) = fields;
923*38fd1498Szrj   fields = field;
924*38fd1498Szrj 
925*38fd1498Szrj   /* next pointer */
926*38fd1498Szrj   field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
927*38fd1498Szrj 		      build_pointer_type (build_qualified_type
928*38fd1498Szrj 					  (type, TYPE_QUAL_CONST)));
929*38fd1498Szrj   DECL_CHAIN (field) = fields;
930*38fd1498Szrj   fields = field;
931*38fd1498Szrj 
932*38fd1498Szrj   /* stamp */
933*38fd1498Szrj   field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
934*38fd1498Szrj 		      get_gcov_unsigned_t ());
935*38fd1498Szrj   DECL_CHAIN (field) = fields;
936*38fd1498Szrj   fields = field;
937*38fd1498Szrj 
938*38fd1498Szrj   /* Filename */
939*38fd1498Szrj   field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
940*38fd1498Szrj 		      build_pointer_type (build_qualified_type
941*38fd1498Szrj 					  (char_type_node, TYPE_QUAL_CONST)));
942*38fd1498Szrj   DECL_CHAIN (field) = fields;
943*38fd1498Szrj   fields = field;
944*38fd1498Szrj 
945*38fd1498Szrj   /* merge fn array */
946*38fd1498Szrj   merge_fn_type
947*38fd1498Szrj     = build_function_type_list (void_type_node,
948*38fd1498Szrj 				build_pointer_type (get_gcov_type ()),
949*38fd1498Szrj 				get_gcov_unsigned_t (), NULL_TREE);
950*38fd1498Szrj   merge_fn_type
951*38fd1498Szrj     = build_array_type (build_pointer_type (merge_fn_type),
952*38fd1498Szrj 			build_index_type (size_int (GCOV_COUNTERS - 1)));
953*38fd1498Szrj   field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
954*38fd1498Szrj 		      merge_fn_type);
955*38fd1498Szrj   DECL_CHAIN (field) = fields;
956*38fd1498Szrj   fields = field;
957*38fd1498Szrj 
958*38fd1498Szrj   /* n_functions */
959*38fd1498Szrj   field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
960*38fd1498Szrj 		      get_gcov_unsigned_t ());
961*38fd1498Szrj   DECL_CHAIN (field) = fields;
962*38fd1498Szrj   fields = field;
963*38fd1498Szrj 
964*38fd1498Szrj   /* function_info pointer pointer */
965*38fd1498Szrj   fn_info_ptr_type = build_pointer_type
966*38fd1498Szrj     (build_qualified_type (fn_info_ptr_type, TYPE_QUAL_CONST));
967*38fd1498Szrj   field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE,
968*38fd1498Szrj 		      fn_info_ptr_type);
969*38fd1498Szrj   DECL_CHAIN (field) = fields;
970*38fd1498Szrj   fields = field;
971*38fd1498Szrj 
972*38fd1498Szrj   finish_builtin_struct (type, "__gcov_info", fields, NULL_TREE);
973*38fd1498Szrj }
974*38fd1498Szrj 
975*38fd1498Szrj /* Returns a CONSTRUCTOR for the gcov_info object.  INFO_TYPE is the
976*38fd1498Szrj    gcov_info structure type, FN_ARY is the array of pointers to
977*38fd1498Szrj    function info objects.  */
978*38fd1498Szrj 
979*38fd1498Szrj static tree
980*38fd1498Szrj build_info (tree info_type, tree fn_ary)
981*38fd1498Szrj {
982*38fd1498Szrj   tree info_fields = TYPE_FIELDS (info_type);
983*38fd1498Szrj   tree merge_fn_type, n_funcs;
984*38fd1498Szrj   unsigned ix;
985*38fd1498Szrj   tree filename_string;
986*38fd1498Szrj   int da_file_name_len;
987*38fd1498Szrj   vec<constructor_elt, va_gc> *v1 = NULL;
988*38fd1498Szrj   vec<constructor_elt, va_gc> *v2 = NULL;
989*38fd1498Szrj 
990*38fd1498Szrj   /* Version ident */
991*38fd1498Szrj   CONSTRUCTOR_APPEND_ELT (v1, info_fields,
992*38fd1498Szrj 			  build_int_cstu (TREE_TYPE (info_fields),
993*38fd1498Szrj 					  GCOV_VERSION));
994*38fd1498Szrj   info_fields = DECL_CHAIN (info_fields);
995*38fd1498Szrj 
996*38fd1498Szrj   /* next -- NULL */
997*38fd1498Szrj   CONSTRUCTOR_APPEND_ELT (v1, info_fields, null_pointer_node);
998*38fd1498Szrj   info_fields = DECL_CHAIN (info_fields);
999*38fd1498Szrj 
1000*38fd1498Szrj   /* stamp */
1001*38fd1498Szrj   CONSTRUCTOR_APPEND_ELT (v1, info_fields,
1002*38fd1498Szrj 			  build_int_cstu (TREE_TYPE (info_fields),
1003*38fd1498Szrj 					  bbg_file_stamp));
1004*38fd1498Szrj   info_fields = DECL_CHAIN (info_fields);
1005*38fd1498Szrj 
1006*38fd1498Szrj   /* Filename */
1007*38fd1498Szrj   da_file_name_len = strlen (da_file_name);
1008*38fd1498Szrj   filename_string = build_string (da_file_name_len + 1, da_file_name);
1009*38fd1498Szrj   TREE_TYPE (filename_string) = build_array_type
1010*38fd1498Szrj     (char_type_node, build_index_type (size_int (da_file_name_len)));
1011*38fd1498Szrj   CONSTRUCTOR_APPEND_ELT (v1, info_fields,
1012*38fd1498Szrj 			  build1 (ADDR_EXPR, TREE_TYPE (info_fields),
1013*38fd1498Szrj 				  filename_string));
1014*38fd1498Szrj   info_fields = DECL_CHAIN (info_fields);
1015*38fd1498Szrj 
1016*38fd1498Szrj   /* merge fn array -- NULL slots indicate unmeasured counters */
1017*38fd1498Szrj   merge_fn_type = TREE_TYPE (TREE_TYPE (info_fields));
1018*38fd1498Szrj   for (ix = 0; ix != GCOV_COUNTERS; ix++)
1019*38fd1498Szrj     {
1020*38fd1498Szrj       tree ptr = null_pointer_node;
1021*38fd1498Szrj 
1022*38fd1498Szrj       if ((1u << ix) & prg_ctr_mask)
1023*38fd1498Szrj 	{
1024*38fd1498Szrj 	  tree merge_fn = build_decl (BUILTINS_LOCATION,
1025*38fd1498Szrj 				      FUNCTION_DECL,
1026*38fd1498Szrj 				      get_identifier (ctr_merge_functions[ix]),
1027*38fd1498Szrj 				      TREE_TYPE (merge_fn_type));
1028*38fd1498Szrj 	  DECL_EXTERNAL (merge_fn) = 1;
1029*38fd1498Szrj 	  TREE_PUBLIC (merge_fn) = 1;
1030*38fd1498Szrj 	  DECL_ARTIFICIAL (merge_fn) = 1;
1031*38fd1498Szrj 	  TREE_NOTHROW (merge_fn) = 1;
1032*38fd1498Szrj 	  /* Initialize assembler name so we can stream out. */
1033*38fd1498Szrj 	  DECL_ASSEMBLER_NAME (merge_fn);
1034*38fd1498Szrj 	  ptr = build1 (ADDR_EXPR, merge_fn_type, merge_fn);
1035*38fd1498Szrj 	}
1036*38fd1498Szrj       CONSTRUCTOR_APPEND_ELT (v2, NULL, ptr);
1037*38fd1498Szrj     }
1038*38fd1498Szrj   CONSTRUCTOR_APPEND_ELT (v1, info_fields,
1039*38fd1498Szrj 			  build_constructor (TREE_TYPE (info_fields), v2));
1040*38fd1498Szrj   info_fields = DECL_CHAIN (info_fields);
1041*38fd1498Szrj 
1042*38fd1498Szrj   /* n_functions */
1043*38fd1498Szrj   n_funcs = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (fn_ary)));
1044*38fd1498Szrj   n_funcs = fold_build2 (PLUS_EXPR, TREE_TYPE (info_fields),
1045*38fd1498Szrj 			 n_funcs, size_one_node);
1046*38fd1498Szrj   CONSTRUCTOR_APPEND_ELT (v1, info_fields, n_funcs);
1047*38fd1498Szrj   info_fields = DECL_CHAIN (info_fields);
1048*38fd1498Szrj 
1049*38fd1498Szrj   /* functions */
1050*38fd1498Szrj   CONSTRUCTOR_APPEND_ELT (v1, info_fields,
1051*38fd1498Szrj 			  build1 (ADDR_EXPR, TREE_TYPE (info_fields), fn_ary));
1052*38fd1498Szrj   info_fields = DECL_CHAIN (info_fields);
1053*38fd1498Szrj 
1054*38fd1498Szrj   gcc_assert (!info_fields);
1055*38fd1498Szrj   return build_constructor (info_type, v1);
1056*38fd1498Szrj }
1057*38fd1498Szrj 
1058*38fd1498Szrj /* Generate the constructor function to call __gcov_init.  */
1059*38fd1498Szrj 
1060*38fd1498Szrj static void
1061*38fd1498Szrj build_init_ctor (tree gcov_info_type)
1062*38fd1498Szrj {
1063*38fd1498Szrj   tree ctor, stmt, init_fn;
1064*38fd1498Szrj 
1065*38fd1498Szrj   /* Build a decl for __gcov_init.  */
1066*38fd1498Szrj   init_fn = build_pointer_type (gcov_info_type);
1067*38fd1498Szrj   init_fn = build_function_type_list (void_type_node, init_fn, NULL);
1068*38fd1498Szrj   init_fn = build_decl (BUILTINS_LOCATION, FUNCTION_DECL,
1069*38fd1498Szrj 			get_identifier ("__gcov_init"), init_fn);
1070*38fd1498Szrj   TREE_PUBLIC (init_fn) = 1;
1071*38fd1498Szrj   DECL_EXTERNAL (init_fn) = 1;
1072*38fd1498Szrj   DECL_ASSEMBLER_NAME (init_fn);
1073*38fd1498Szrj 
1074*38fd1498Szrj   /* Generate a call to __gcov_init(&gcov_info).  */
1075*38fd1498Szrj   ctor = NULL;
1076*38fd1498Szrj   stmt = build_fold_addr_expr (gcov_info_var);
1077*38fd1498Szrj   stmt = build_call_expr (init_fn, 1, stmt);
1078*38fd1498Szrj   append_to_statement_list (stmt, &ctor);
1079*38fd1498Szrj 
1080*38fd1498Szrj   /* Generate a constructor to run it.  */
1081*38fd1498Szrj   int priority = SUPPORTS_INIT_PRIORITY
1082*38fd1498Szrj     ? MAX_RESERVED_INIT_PRIORITY: DEFAULT_INIT_PRIORITY;
1083*38fd1498Szrj   cgraph_build_static_cdtor ('I', ctor, priority);
1084*38fd1498Szrj }
1085*38fd1498Szrj 
1086*38fd1498Szrj /* Generate the destructor function to call __gcov_exit.  */
1087*38fd1498Szrj 
1088*38fd1498Szrj static void
1089*38fd1498Szrj build_gcov_exit_decl (void)
1090*38fd1498Szrj {
1091*38fd1498Szrj   tree init_fn = build_function_type_list (void_type_node, void_type_node,
1092*38fd1498Szrj 					   NULL);
1093*38fd1498Szrj   init_fn = build_decl (BUILTINS_LOCATION, FUNCTION_DECL,
1094*38fd1498Szrj 			get_identifier ("__gcov_exit"), init_fn);
1095*38fd1498Szrj   TREE_PUBLIC (init_fn) = 1;
1096*38fd1498Szrj   DECL_EXTERNAL (init_fn) = 1;
1097*38fd1498Szrj   DECL_ASSEMBLER_NAME (init_fn);
1098*38fd1498Szrj 
1099*38fd1498Szrj   /* Generate a call to __gcov_exit ().  */
1100*38fd1498Szrj   tree dtor = NULL;
1101*38fd1498Szrj   tree stmt = build_call_expr (init_fn, 0);
1102*38fd1498Szrj   append_to_statement_list (stmt, &dtor);
1103*38fd1498Szrj 
1104*38fd1498Szrj   /* Generate a destructor to run it.  */
1105*38fd1498Szrj   int priority = SUPPORTS_INIT_PRIORITY
1106*38fd1498Szrj     ? MAX_RESERVED_INIT_PRIORITY: DEFAULT_INIT_PRIORITY;
1107*38fd1498Szrj 
1108*38fd1498Szrj   cgraph_build_static_cdtor ('D', dtor, priority);
1109*38fd1498Szrj }
1110*38fd1498Szrj 
1111*38fd1498Szrj /* Create the gcov_info types and object.  Generate the constructor
1112*38fd1498Szrj    function to call __gcov_init.  Does not generate the initializer
1113*38fd1498Szrj    for the object.  Returns TRUE if coverage data is being emitted.  */
1114*38fd1498Szrj 
1115*38fd1498Szrj static bool
1116*38fd1498Szrj coverage_obj_init (void)
1117*38fd1498Szrj {
1118*38fd1498Szrj   tree gcov_info_type;
1119*38fd1498Szrj   unsigned n_counters = 0;
1120*38fd1498Szrj   unsigned ix;
1121*38fd1498Szrj   struct coverage_data *fn;
1122*38fd1498Szrj   struct coverage_data **fn_prev;
1123*38fd1498Szrj   char name_buf[32];
1124*38fd1498Szrj 
1125*38fd1498Szrj   no_coverage = 1; /* Disable any further coverage.  */
1126*38fd1498Szrj 
1127*38fd1498Szrj   if (!prg_ctr_mask)
1128*38fd1498Szrj     return false;
1129*38fd1498Szrj 
1130*38fd1498Szrj   if (symtab->dump_file)
1131*38fd1498Szrj     fprintf (symtab->dump_file, "Using data file %s\n", da_file_name);
1132*38fd1498Szrj 
1133*38fd1498Szrj   /* Prune functions.  */
1134*38fd1498Szrj   for (fn_prev = &functions_head; (fn = *fn_prev);)
1135*38fd1498Szrj     if (DECL_STRUCT_FUNCTION (fn->fn_decl))
1136*38fd1498Szrj       fn_prev = &fn->next;
1137*38fd1498Szrj     else
1138*38fd1498Szrj       /* The function is not being emitted, remove from list.  */
1139*38fd1498Szrj       *fn_prev = fn->next;
1140*38fd1498Szrj 
1141*38fd1498Szrj   if (functions_head == NULL)
1142*38fd1498Szrj     return false;
1143*38fd1498Szrj 
1144*38fd1498Szrj   for (ix = 0; ix != GCOV_COUNTERS; ix++)
1145*38fd1498Szrj     if ((1u << ix) & prg_ctr_mask)
1146*38fd1498Szrj       n_counters++;
1147*38fd1498Szrj 
1148*38fd1498Szrj   /* Build the info and fn_info types.  These are mutually recursive.  */
1149*38fd1498Szrj   gcov_info_type = lang_hooks.types.make_type (RECORD_TYPE);
1150*38fd1498Szrj   gcov_fn_info_type = lang_hooks.types.make_type (RECORD_TYPE);
1151*38fd1498Szrj   build_fn_info_type (gcov_fn_info_type, n_counters, gcov_info_type);
1152*38fd1498Szrj   gcov_info_type = lang_hooks.types.make_type (RECORD_TYPE);
1153*38fd1498Szrj   gcov_fn_info_ptr_type = build_pointer_type
1154*38fd1498Szrj     (build_qualified_type (gcov_fn_info_type, TYPE_QUAL_CONST));
1155*38fd1498Szrj   build_info_type (gcov_info_type, gcov_fn_info_ptr_type);
1156*38fd1498Szrj 
1157*38fd1498Szrj   /* Build the gcov info var, this is referred to in its own
1158*38fd1498Szrj      initializer.  */
1159*38fd1498Szrj   gcov_info_var = build_decl (BUILTINS_LOCATION,
1160*38fd1498Szrj 			      VAR_DECL, NULL_TREE, gcov_info_type);
1161*38fd1498Szrj   TREE_STATIC (gcov_info_var) = 1;
1162*38fd1498Szrj   ASM_GENERATE_INTERNAL_LABEL (name_buf, "LPBX", 0);
1163*38fd1498Szrj   DECL_NAME (gcov_info_var) = get_identifier (name_buf);
1164*38fd1498Szrj 
1165*38fd1498Szrj   build_init_ctor (gcov_info_type);
1166*38fd1498Szrj   build_gcov_exit_decl ();
1167*38fd1498Szrj 
1168*38fd1498Szrj   return true;
1169*38fd1498Szrj }
1170*38fd1498Szrj 
1171*38fd1498Szrj /* Generate the coverage function info for FN and DATA.  Append a
1172*38fd1498Szrj    pointer to that object to CTOR and return the appended CTOR.  */
1173*38fd1498Szrj 
1174*38fd1498Szrj static vec<constructor_elt, va_gc> *
1175*38fd1498Szrj coverage_obj_fn (vec<constructor_elt, va_gc> *ctor, tree fn,
1176*38fd1498Szrj 		 struct coverage_data const *data)
1177*38fd1498Szrj {
1178*38fd1498Szrj   tree init = build_fn_info (data, gcov_fn_info_type, gcov_info_var);
1179*38fd1498Szrj   tree var = build_var (fn, gcov_fn_info_type, -1);
1180*38fd1498Szrj 
1181*38fd1498Szrj   DECL_INITIAL (var) = init;
1182*38fd1498Szrj   varpool_node::finalize_decl (var);
1183*38fd1498Szrj 
1184*38fd1498Szrj   CONSTRUCTOR_APPEND_ELT (ctor, NULL,
1185*38fd1498Szrj 			  build1 (ADDR_EXPR, gcov_fn_info_ptr_type, var));
1186*38fd1498Szrj   return ctor;
1187*38fd1498Szrj }
1188*38fd1498Szrj 
1189*38fd1498Szrj /* Finalize the coverage data.  Generates the array of pointers to
1190*38fd1498Szrj    function objects from CTOR.  Generate the gcov_info initializer.  */
1191*38fd1498Szrj 
1192*38fd1498Szrj static void
1193*38fd1498Szrj coverage_obj_finish (vec<constructor_elt, va_gc> *ctor)
1194*38fd1498Szrj {
1195*38fd1498Szrj   unsigned n_functions = vec_safe_length (ctor);
1196*38fd1498Szrj   tree fn_info_ary_type = build_array_type
1197*38fd1498Szrj     (build_qualified_type (gcov_fn_info_ptr_type, TYPE_QUAL_CONST),
1198*38fd1498Szrj      build_index_type (size_int (n_functions - 1)));
1199*38fd1498Szrj   tree fn_info_ary = build_decl (BUILTINS_LOCATION, VAR_DECL, NULL_TREE,
1200*38fd1498Szrj 				 fn_info_ary_type);
1201*38fd1498Szrj   char name_buf[32];
1202*38fd1498Szrj 
1203*38fd1498Szrj   TREE_STATIC (fn_info_ary) = 1;
1204*38fd1498Szrj   ASM_GENERATE_INTERNAL_LABEL (name_buf, "LPBX", 1);
1205*38fd1498Szrj   DECL_NAME (fn_info_ary) = get_identifier (name_buf);
1206*38fd1498Szrj   DECL_INITIAL (fn_info_ary) = build_constructor (fn_info_ary_type, ctor);
1207*38fd1498Szrj   varpool_node::finalize_decl (fn_info_ary);
1208*38fd1498Szrj 
1209*38fd1498Szrj   DECL_INITIAL (gcov_info_var)
1210*38fd1498Szrj     = build_info (TREE_TYPE (gcov_info_var), fn_info_ary);
1211*38fd1498Szrj   varpool_node::finalize_decl (gcov_info_var);
1212*38fd1498Szrj }
1213*38fd1498Szrj 
1214*38fd1498Szrj /* Perform file-level initialization. Read in data file, generate name
1215*38fd1498Szrj    of notes file.  */
1216*38fd1498Szrj 
1217*38fd1498Szrj void
1218*38fd1498Szrj coverage_init (const char *filename)
1219*38fd1498Szrj {
1220*38fd1498Szrj   int len = strlen (filename);
1221*38fd1498Szrj   int prefix_len = 0;
1222*38fd1498Szrj 
1223*38fd1498Szrj   /* Since coverage_init is invoked very early, before the pass
1224*38fd1498Szrj      manager, we need to set up the dumping explicitly. This is
1225*38fd1498Szrj      similar to the handling in finish_optimization_passes.  */
1226*38fd1498Szrj   int profile_pass_num =
1227*38fd1498Szrj     g->get_passes ()->get_pass_profile ()->static_pass_number;
1228*38fd1498Szrj   g->get_dumps ()->dump_start (profile_pass_num, NULL);
1229*38fd1498Szrj 
1230*38fd1498Szrj   if (!profile_data_prefix && !IS_ABSOLUTE_PATH (filename))
1231*38fd1498Szrj     profile_data_prefix = getpwd ();
1232*38fd1498Szrj 
1233*38fd1498Szrj   if (profile_data_prefix)
1234*38fd1498Szrj     prefix_len = strlen (profile_data_prefix);
1235*38fd1498Szrj 
1236*38fd1498Szrj   /* Name of da file.  */
1237*38fd1498Szrj   da_file_name = XNEWVEC (char, len + strlen (GCOV_DATA_SUFFIX)
1238*38fd1498Szrj 			  + prefix_len + 2);
1239*38fd1498Szrj 
1240*38fd1498Szrj   if (profile_data_prefix)
1241*38fd1498Szrj     {
1242*38fd1498Szrj       memcpy (da_file_name, profile_data_prefix, prefix_len);
1243*38fd1498Szrj       da_file_name[prefix_len++] = '/';
1244*38fd1498Szrj     }
1245*38fd1498Szrj   memcpy (da_file_name + prefix_len, filename, len);
1246*38fd1498Szrj   strcpy (da_file_name + prefix_len + len, GCOV_DATA_SUFFIX);
1247*38fd1498Szrj 
1248*38fd1498Szrj   bbg_file_stamp = local_tick;
1249*38fd1498Szrj 
1250*38fd1498Szrj   if (flag_auto_profile)
1251*38fd1498Szrj     read_autofdo_file ();
1252*38fd1498Szrj   else if (flag_branch_probabilities)
1253*38fd1498Szrj     read_counts_file ();
1254*38fd1498Szrj 
1255*38fd1498Szrj   /* Name of bbg file.  */
1256*38fd1498Szrj   if (flag_test_coverage && !flag_compare_debug)
1257*38fd1498Szrj     {
1258*38fd1498Szrj       bbg_file_name = XNEWVEC (char, len + strlen (GCOV_NOTE_SUFFIX) + 1);
1259*38fd1498Szrj       memcpy (bbg_file_name, filename, len);
1260*38fd1498Szrj       strcpy (bbg_file_name + len, GCOV_NOTE_SUFFIX);
1261*38fd1498Szrj 
1262*38fd1498Szrj       if (!gcov_open (bbg_file_name, -1))
1263*38fd1498Szrj 	{
1264*38fd1498Szrj 	  error ("cannot open %s", bbg_file_name);
1265*38fd1498Szrj 	  bbg_file_name = NULL;
1266*38fd1498Szrj 	}
1267*38fd1498Szrj       else
1268*38fd1498Szrj 	{
1269*38fd1498Szrj 	  gcov_write_unsigned (GCOV_NOTE_MAGIC);
1270*38fd1498Szrj 	  gcov_write_unsigned (GCOV_VERSION);
1271*38fd1498Szrj 	  gcov_write_unsigned (bbg_file_stamp);
1272*38fd1498Szrj 
1273*38fd1498Szrj 	  /* Do not support has_unexecuted_blocks for Ada.  */
1274*38fd1498Szrj 	  gcov_write_unsigned (strcmp (lang_hooks.name, "GNU Ada") != 0);
1275*38fd1498Szrj 	}
1276*38fd1498Szrj     }
1277*38fd1498Szrj 
1278*38fd1498Szrj   g->get_dumps ()->dump_finish (profile_pass_num);
1279*38fd1498Szrj }
1280*38fd1498Szrj 
1281*38fd1498Szrj /* Performs file-level cleanup.  Close notes file, generate coverage
1282*38fd1498Szrj    variables and constructor.  */
1283*38fd1498Szrj 
1284*38fd1498Szrj void
1285*38fd1498Szrj coverage_finish (void)
1286*38fd1498Szrj {
1287*38fd1498Szrj   if (bbg_file_name && gcov_close ())
1288*38fd1498Szrj     unlink (bbg_file_name);
1289*38fd1498Szrj 
1290*38fd1498Szrj   if (!flag_branch_probabilities && flag_test_coverage
1291*38fd1498Szrj       && (!local_tick || local_tick == (unsigned)-1))
1292*38fd1498Szrj     /* Only remove the da file, if we're emitting coverage code and
1293*38fd1498Szrj        cannot uniquely stamp it.  If we can stamp it, libgcov will DTRT.  */
1294*38fd1498Szrj     unlink (da_file_name);
1295*38fd1498Szrj 
1296*38fd1498Szrj   if (coverage_obj_init ())
1297*38fd1498Szrj     {
1298*38fd1498Szrj       vec<constructor_elt, va_gc> *fn_ctor = NULL;
1299*38fd1498Szrj       struct coverage_data *fn;
1300*38fd1498Szrj 
1301*38fd1498Szrj       for (fn = functions_head; fn; fn = fn->next)
1302*38fd1498Szrj 	fn_ctor = coverage_obj_fn (fn_ctor, fn->fn_decl, fn);
1303*38fd1498Szrj       coverage_obj_finish (fn_ctor);
1304*38fd1498Szrj     }
1305*38fd1498Szrj 
1306*38fd1498Szrj   XDELETEVEC (da_file_name);
1307*38fd1498Szrj   da_file_name = NULL;
1308*38fd1498Szrj }
1309*38fd1498Szrj 
1310*38fd1498Szrj #include "gt-coverage.h"
1311