]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/coverage.c
* vec.h: Comment improvements.
[thirdparty/gcc.git] / gcc / coverage.c
CommitLineData
ca29da43
NS
1/* Read and write coverage files, and associated functionality.
2 Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, 1999,
7da1799a 3 2000, 2001, 2003, 2004 Free Software Foundation, Inc.
ca29da43
NS
4 Contributed by James E. Wilson, UC Berkeley/Cygnus Support;
5 based on some ideas from Dain Samples of UC Berkeley.
6 Further mangling by Bob Manson, Cygnus Support.
7 Further mangled by Nathan Sidwell, CodeSourcery
8
9This file is part of GCC.
10
11GCC is free software; you can redistribute it and/or modify it under
12the terms of the GNU General Public License as published by the Free
13Software Foundation; either version 2, or (at your option) any later
14version.
15
16GCC is distributed in the hope that it will be useful, but WITHOUT ANY
17WARRANTY; without even the implied warranty of MERCHANTABILITY or
18FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19for more details.
20
21You should have received a copy of the GNU General Public License
22along with GCC; see the file COPYING. If not, write to the Free
23Software Foundation, 59 Temple Place - Suite 330, Boston, MA
2402111-1307, USA. */
25
26
27#define GCOV_LINKAGE
28
29#include "config.h"
30#include "system.h"
31#include "coretypes.h"
32#include "tm.h"
33#include "rtl.h"
34#include "tree.h"
35#include "flags.h"
36#include "output.h"
37#include "regs.h"
38#include "expr.h"
39#include "function.h"
40#include "toplev.h"
41#include "ggc.h"
ca29da43 42#include "coverage.h"
ca29da43
NS
43#include "langhooks.h"
44#include "hashtab.h"
c9b9aa64
RH
45#include "tree-iterator.h"
46#include "cgraph.h"
ca29da43
NS
47
48#include "gcov-io.c"
49
50struct function_list
51{
159b3be1
AJ
52 struct function_list *next; /* next function */
53 unsigned ident; /* function ident */
cdb23767
NS
54 unsigned checksum; /* function checksum */
55 unsigned n_ctrs[GCOV_COUNTERS];/* number of counters. */
ca29da43
NS
56};
57
58/* Counts information for a function. */
59typedef struct counts_entry
60{
61 /* We hash by */
796621e8 62 unsigned ident;
cdb23767 63 unsigned ctr;
159b3be1 64
ca29da43
NS
65 /* Store */
66 unsigned checksum;
ca29da43 67 gcov_type *counts;
cdb23767 68 struct gcov_ctr_summary summary;
ca29da43
NS
69
70 /* Workspace */
71 struct counts_entry *chain;
159b3be1 72
ca29da43
NS
73} counts_entry_t;
74
75static struct function_list *functions_head = 0;
76static struct function_list **functions_tail = &functions_head;
6d70e6be 77static unsigned no_coverage = 0;
ca29da43 78
cdb23767
NS
79/* Cumulative counter information for whole program. */
80static unsigned prg_ctr_mask; /* Mask of counter types generated. */
6d70e6be 81static unsigned prg_n_ctrs[GCOV_COUNTERS]; /* Total counters allocated. */
ca29da43 82
cdb23767 83/* Counter information for current function. */
71c0e7fc 84static unsigned fn_ctr_mask; /* Mask of counters used. */
6d70e6be
NS
85static unsigned fn_n_ctrs[GCOV_COUNTERS]; /* Counters allocated. */
86static unsigned fn_b_ctrs[GCOV_COUNTERS]; /* Allocation base. */
ca29da43
NS
87
88/* Name of the output file for coverage output file. */
89static char *bbg_file_name;
90static unsigned bbg_file_opened;
91static int bbg_function_announced;
92
93/* Name of the count data file. */
94static char *da_file_name;
95
96/* Hash table of count data. */
97static htab_t counts_hash = NULL;
98
6de9cd9a
DN
99/* Trees representing the counter table arrays. */
100static GTY(()) tree tree_ctr_tables[GCOV_COUNTERS];
101
102/* The names of the counter tables. Not used if we're
103 generating counters at tree level. */
cdb23767 104static GTY(()) rtx ctr_labels[GCOV_COUNTERS];
ca29da43 105
09780dfb 106/* The names of merge functions for counters. */
9b514d25
NS
107static const char *const ctr_merge_functions[GCOV_COUNTERS] = GCOV_MERGE_FUNCTIONS;
108static const char *const ctr_names[GCOV_COUNTERS] = GCOV_COUNTER_NAMES;
09780dfb 109
ca29da43 110/* Forward declarations. */
159b3be1
AJ
111static hashval_t htab_counts_entry_hash (const void *);
112static int htab_counts_entry_eq (const void *, const void *);
113static void htab_counts_entry_del (void *);
114static void read_counts_file (void);
115static unsigned compute_checksum (void);
20c361f3 116static unsigned coverage_checksum_string (unsigned, const char *);
159b3be1
AJ
117static tree build_fn_info_type (unsigned);
118static tree build_fn_info_value (const struct function_list *, tree);
119static tree build_ctr_info_type (void);
120static tree build_ctr_info_value (unsigned, tree);
121static tree build_gcov_info (void);
122static void create_coverage (void);
ca29da43
NS
123
124\f
125static hashval_t
159b3be1 126htab_counts_entry_hash (const void *of)
ca29da43
NS
127{
128 const counts_entry_t *entry = of;
129
796621e8 130 return entry->ident * GCOV_COUNTERS + entry->ctr;
ca29da43
NS
131}
132
133static int
159b3be1 134htab_counts_entry_eq (const void *of1, const void *of2)
ca29da43
NS
135{
136 const counts_entry_t *entry1 = of1;
137 const counts_entry_t *entry2 = of2;
138
796621e8 139 return entry1->ident == entry2->ident && entry1->ctr == entry2->ctr;
ca29da43
NS
140}
141
142static void
159b3be1 143htab_counts_entry_del (void *of)
ca29da43
NS
144{
145 counts_entry_t *entry = of;
146
ca29da43
NS
147 free (entry->counts);
148 free (entry);
149}
150
151/* Read in the counts file, if available. */
152
153static void
159b3be1 154read_counts_file (void)
ca29da43 155{
9b514d25 156 gcov_unsigned_t fn_ident = 0;
160e2e4f 157 gcov_unsigned_t checksum = -1;
ca29da43
NS
158 counts_entry_t *summaried = NULL;
159 unsigned seen_summary = 0;
7d63a2fa 160 gcov_unsigned_t tag;
24a4a033 161 int is_error = 0;
7d63a2fa 162
ca29da43
NS
163 if (!gcov_open (da_file_name, 1))
164 return;
159b3be1 165
160e2e4f 166 if (!gcov_magic (gcov_read_unsigned (), GCOV_DATA_MAGIC))
ca29da43
NS
167 {
168 warning ("`%s' is not a gcov data file", da_file_name);
169 gcov_close ();
170 return;
171 }
160e2e4f 172 else if ((tag = gcov_read_unsigned ()) != GCOV_VERSION)
ca29da43 173 {
330d2e2a
NS
174 char v[4], e[4];
175
176 GCOV_UNSIGNED2STRING (v, tag);
177 GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
159b3be1 178
cb83302c
SB
179 warning ("`%s' is version `%.*s', expected version `%.*s'",
180 da_file_name, 4, v, 4, e);
ca29da43
NS
181 gcov_close ();
182 return;
183 }
159b3be1 184
4ed43216 185 /* Read and discard the stamp. */
dd486eb2
NS
186 gcov_read_unsigned ();
187
ca29da43
NS
188 counts_hash = htab_create (10,
189 htab_counts_entry_hash, htab_counts_entry_eq,
190 htab_counts_entry_del);
7d63a2fa 191 while ((tag = gcov_read_unsigned ()))
ca29da43 192 {
7d63a2fa 193 gcov_unsigned_t length;
9b514d25 194 gcov_position_t offset;
159b3be1 195
ca29da43
NS
196 length = gcov_read_unsigned ();
197 offset = gcov_position ();
198 if (tag == GCOV_TAG_FUNCTION)
199 {
796621e8 200 fn_ident = gcov_read_unsigned ();
ca29da43
NS
201 checksum = gcov_read_unsigned ();
202 if (seen_summary)
203 {
204 /* We have already seen a summary, this means that this
205 new function begins a new set of program runs. We
206 must unlink the summaried chain. */
207 counts_entry_t *entry, *chain;
159b3be1 208
ca29da43
NS
209 for (entry = summaried; entry; entry = chain)
210 {
211 chain = entry->chain;
ca29da43
NS
212 entry->chain = NULL;
213 }
214 summaried = NULL;
215 seen_summary = 0;
216 }
217 }
218 else if (tag == GCOV_TAG_PROGRAM_SUMMARY)
219 {
220 counts_entry_t *entry;
221 struct gcov_summary summary;
159b3be1 222
ca29da43
NS
223 gcov_read_summary (&summary);
224 seen_summary = 1;
225 for (entry = summaried; entry; entry = entry->chain)
226 {
cdb23767 227 struct gcov_ctr_summary *csum = &summary.ctrs[entry->ctr];
159b3be1 228
cdb23767
NS
229 entry->summary.runs += csum->runs;
230 entry->summary.sum_all += csum->sum_all;
231 if (entry->summary.run_max < csum->run_max)
232 entry->summary.run_max = csum->run_max;
233 entry->summary.sum_max += csum->sum_max;
ca29da43
NS
234 }
235 }
796621e8 236 else if (GCOV_TAG_IS_COUNTER (tag) && fn_ident)
ca29da43
NS
237 {
238 counts_entry_t **slot, *entry, elt;
330d2e2a 239 unsigned n_counts = GCOV_TAG_COUNTER_NUM (length);
ca29da43
NS
240 unsigned ix;
241
796621e8 242 elt.ident = fn_ident;
cdb23767 243 elt.ctr = GCOV_COUNTER_FOR_TAG (tag);
ca29da43
NS
244
245 slot = (counts_entry_t **) htab_find_slot
246 (counts_hash, &elt, INSERT);
247 entry = *slot;
248 if (!entry)
249 {
cdb23767 250 *slot = entry = xcalloc (1, sizeof (counts_entry_t));
796621e8 251 entry->ident = elt.ident;
cdb23767 252 entry->ctr = elt.ctr;
ca29da43 253 entry->checksum = checksum;
cdb23767 254 entry->summary.num = n_counts;
ca29da43
NS
255 entry->counts = xcalloc (n_counts, sizeof (gcov_type));
256 }
24a4a033 257 else if (entry->checksum != checksum)
ca29da43 258 {
24a4a033
JH
259 error ("coverage mismatch for function %u while reading execution counters.",
260 fn_ident);
261 error ("checksum is %x instead of %x", entry->checksum, checksum);
262 htab_delete (counts_hash);
263 break;
264 }
265 else if (entry->summary.num != n_counts)
266 {
267 error ("coverage mismatch for function %u while reading execution counters.",
268 fn_ident);
269 error ("number of counters is %d instead of %d", entry->summary.num, n_counts);
ca29da43
NS
270 htab_delete (counts_hash);
271 break;
272 }
9b514d25
NS
273 else if (elt.ctr >= GCOV_COUNTERS_SUMMABLE)
274 {
24a4a033
JH
275 error ("cannot merge separate %s counters for function %u",
276 ctr_names[elt.ctr], fn_ident);
9b514d25
NS
277 goto skip_merge;
278 }
279
280 if (elt.ctr < GCOV_COUNTERS_SUMMABLE
281 /* This should always be true for a just allocated entry,
159b3be1
AJ
282 and always false for an existing one. Check this way, in
283 case the gcov file is corrupt. */
9b514d25 284 && (!entry->chain || summaried != entry))
ca29da43
NS
285 {
286 entry->chain = summaried;
287 summaried = entry;
288 }
289 for (ix = 0; ix != n_counts; ix++)
290 entry->counts[ix] += gcov_read_counter ();
9b514d25 291 skip_merge:;
ca29da43 292 }
474f141e 293 gcov_sync (offset, length);
24a4a033 294 if ((is_error = gcov_is_error ()))
00cf2913
NS
295 {
296 error (is_error < 0 ? "`%s' has overflowed" : "`%s' is corrupted",
297 da_file_name);
298 htab_delete (counts_hash);
299 break;
300 }
7d63a2fa 301 }
159b3be1 302
ca29da43
NS
303 gcov_close ();
304}
305
306/* Returns the counters for a particular tag. */
307
308gcov_type *
cdb23767
NS
309get_coverage_counts (unsigned counter, unsigned expected,
310 const struct gcov_ctr_summary **summary)
ca29da43
NS
311{
312 counts_entry_t *entry, elt;
24a4a033 313 gcov_unsigned_t checksum = -1;
ca29da43 314
71c0e7fc 315 /* No hash table, no counts. */
ca29da43
NS
316 if (!counts_hash)
317 {
318 static int warned = 0;
319
320 if (!warned++)
02307675
R
321 inform ((flag_guess_branch_prob
322 ? "file %s not found, execution counts estimated"
323 : "file %s not found, execution counts assumed to be zero"),
bbfff586 324 da_file_name);
ca29da43
NS
325 return NULL;
326 }
327
6d70e6be 328 elt.ident = current_function_funcdef_no + 1;
cdb23767 329 elt.ctr = counter;
ca29da43
NS
330 entry = htab_find (counts_hash, &elt);
331 if (!entry)
332 {
796621e8
NS
333 warning ("no coverage for function '%s' found.", IDENTIFIER_POINTER
334 (DECL_ASSEMBLER_NAME (current_function_decl)));
ca29da43
NS
335 return 0;
336 }
159b3be1 337
24a4a033
JH
338 checksum = compute_checksum ();
339 if (entry->checksum != checksum)
ca29da43 340 {
24a4a033
JH
341 error ("coverage mismatch for function '%s' while reading counter '%s'.",
342 IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl)),
343 ctr_names[counter]);
344 error ("checksum is %x instead of %x", entry->checksum, checksum);
345 return 0;
346 }
347 else if (entry->summary.num != expected)
348 {
349 error ("coverage mismatch for function '%s' while reading counter '%s'.",
350 IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl)),
351 ctr_names[counter]);
352 error ("number of counters is %d instead of %d", entry->summary.num, expected);
353 return 0;
ca29da43 354 }
159b3be1 355
cdb23767
NS
356 if (summary)
357 *summary = &entry->summary;
ca29da43
NS
358
359 return entry->counts;
360}
cdb23767 361
6356f892 362/* Allocate NUM counters of type COUNTER. Returns nonzero if the
6d70e6be 363 allocation succeeded. */
cdb23767 364
6d70e6be
NS
365int
366coverage_counter_alloc (unsigned counter, unsigned num)
cdb23767 367{
6d70e6be
NS
368 if (no_coverage)
369 return 0;
159b3be1 370
6d70e6be
NS
371 if (!num)
372 return 1;
159b3be1 373
6de9cd9a 374 if (!tree_ctr_tables[counter])
cdb23767
NS
375 {
376 /* Generate and save a copy of this so it can be shared. */
6de9cd9a
DN
377 /* We don't know the size yet; make it big enough that nobody
378 will make any clever transformation on it. */
cdb23767 379 char buf[20];
6de9cd9a
DN
380 tree domain_tree
381 = build_index_type (build_int_2 (1000, 0)); /* replaced later */
382 tree gcov_type_array_type
383 = build_array_type (GCOV_TYPE_NODE, domain_tree);
384 tree_ctr_tables[counter]
385 = build_decl (VAR_DECL, NULL_TREE, gcov_type_array_type);
386 TREE_STATIC (tree_ctr_tables[counter]) = 1;
cdb23767 387 ASM_GENERATE_INTERNAL_LABEL (buf, "LPBX", counter + 1);
6de9cd9a
DN
388 DECL_NAME (tree_ctr_tables[counter]) = get_identifier (buf);
389 DECL_ALIGN (tree_ctr_tables[counter]) = TYPE_ALIGN (GCOV_TYPE_NODE);
cdb23767 390 }
6d70e6be
NS
391 fn_b_ctrs[counter] = fn_n_ctrs[counter];
392 fn_n_ctrs[counter] += num;
393 fn_ctr_mask |= 1 << counter;
394 return 1;
395}
cdb23767 396
6d70e6be
NS
397/* Generate a MEM rtl to access COUNTER NO. */
398
399rtx
6de9cd9a 400rtl_coverage_counter_ref (unsigned counter, unsigned no)
6d70e6be
NS
401{
402 unsigned gcov_size = tree_low_cst (TYPE_SIZE (GCOV_TYPE_NODE), 1);
403 enum machine_mode mode = mode_for_size (gcov_size, MODE_INT, 0);
404 rtx ref;
405
406 if (no >= fn_n_ctrs[counter] - fn_b_ctrs[counter])
407 abort ();
408 no += prg_n_ctrs[counter] + fn_b_ctrs[counter];
6de9cd9a
DN
409 if (!ctr_labels[counter])
410 {
411 ctr_labels[counter] = gen_rtx_SYMBOL_REF (Pmode,
412 ggc_strdup (IDENTIFIER_POINTER (DECL_NAME
413 (tree_ctr_tables[counter]))));
414 SYMBOL_REF_FLAGS (ctr_labels[counter]) = SYMBOL_FLAG_LOCAL;
415 }
9b514d25 416 ref = plus_constant (ctr_labels[counter], gcov_size / BITS_PER_UNIT * no);
cdb23767
NS
417 ref = gen_rtx_MEM (mode, ref);
418 set_mem_alias_set (ref, new_alias_set ());
27ab3e91 419 MEM_NOTRAP_P (ref) = 1;
cdb23767
NS
420
421 return ref;
422}
6de9cd9a
DN
423
424/* Generate a tree to access COUNTER NO. */
425
426tree
427tree_coverage_counter_ref (unsigned counter, unsigned no)
428{
44de5aeb 429 tree domain_type = TYPE_DOMAIN (TREE_TYPE (tree_ctr_tables[counter]));
6de9cd9a
DN
430
431 if (no >= fn_n_ctrs[counter] - fn_b_ctrs[counter])
432 abort ();
433 no += prg_n_ctrs[counter] + fn_b_ctrs[counter];
434
435 /* "no" here is an array index, scaled to bytes later. */
3244e67d
RS
436 return build4 (ARRAY_REF, GCOV_TYPE_NODE, tree_ctr_tables[counter],
437 fold_convert (domain_type, build_int_2 (no, 0)),
438 TYPE_MIN_VALUE (domain_type),
439 size_binop (EXACT_DIV_EXPR, TYPE_SIZE_UNIT (GCOV_TYPE_NODE),
d836edf8 440 size_int (TYPE_ALIGN_UNIT (GCOV_TYPE_NODE))));
6de9cd9a 441}
ca29da43
NS
442\f
443/* Generate a checksum for a string. CHKSUM is the current
71c0e7fc 444 checksum. */
ca29da43
NS
445
446static unsigned
20c361f3 447coverage_checksum_string (unsigned chksum, const char *string)
ca29da43 448{
20c361f3
JH
449 int i;
450 char *dup = NULL;
451
452 /* Look for everything that looks if it were produced by
453 get_file_function_name_long and zero out the second part
454 that may result from flag_random_seed. This is not critical
455 as the checksums are used only for sanity checking. */
456 for (i = 0; string[i]; i++)
ca29da43 457 {
20c361f3
JH
458 if (!strncmp (string + i, "_GLOBAL__", 9))
459 for (i = i + 9; string[i]; i++)
460 if (string[i]=='_')
461 {
462 int y;
463 unsigned seed;
464
465 for (y = 1; y < 9; y++)
466 if (!(string[i + y] >= '0' && string[i + y] <= '9')
467 && !(string[i + y] >= 'A' && string[i + y] <= 'F'))
468 break;
469 if (y != 9 || string[i + 9] != '_')
470 continue;
471 for (y = 10; y < 18; y++)
472 if (!(string[i + y] >= '0' && string[i + y] <= '9')
473 && !(string[i + y] >= 'A' && string[i + y] <= 'F'))
474 break;
475 if (y != 18)
476 continue;
477 if (!sscanf (string + i + 10, "%X", &seed))
478 abort ();
479 if (seed != crc32_string (0, flag_random_seed))
480 continue;
481 string = dup = xstrdup (string);
482 for (y = 10; y < 18; y++)
483 dup[i + y] = '0';
484 break;
485 }
486 break;
ca29da43 487 }
20c361f3
JH
488
489 chksum = crc32_string (chksum, string);
490 if (dup)
491 free (dup);
159b3be1 492
ca29da43
NS
493 return chksum;
494}
495
496/* Compute checksum for the current function. We generate a CRC32. */
497
498static unsigned
159b3be1 499compute_checksum (void)
ca29da43 500{
a281759f
PB
501 expanded_location xloc
502 = expand_location (DECL_SOURCE_LOCATION (current_function_decl));
503 unsigned chksum = xloc.line;
ca29da43 504
a281759f 505 chksum = coverage_checksum_string (chksum, xloc.file);
20c361f3 506 chksum = coverage_checksum_string
ca29da43
NS
507 (chksum, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl)));
508
509 return chksum;
510}
511\f
512/* Begin output to the graph file for the current function.
513 Opens the output file, if not already done. Writes the
6356f892 514 function header, if not already done. Returns nonzero if data
ca29da43
NS
515 should be output. */
516
517int
159b3be1 518coverage_begin_output (void)
ca29da43 519{
6d70e6be
NS
520 if (no_coverage)
521 return 0;
159b3be1 522
ca29da43
NS
523 if (!bbg_function_announced)
524 {
a281759f
PB
525 expanded_location xloc
526 = expand_location (DECL_SOURCE_LOCATION (current_function_decl));
ca29da43 527 unsigned long offset;
159b3be1 528
ca29da43
NS
529 if (!bbg_file_opened)
530 {
531 if (!gcov_open (bbg_file_name, -1))
532 error ("cannot open %s", bbg_file_name);
533 else
534 {
160e2e4f 535 gcov_write_unsigned (GCOV_NOTE_MAGIC);
ca29da43 536 gcov_write_unsigned (GCOV_VERSION);
dd486eb2 537 gcov_write_unsigned (local_tick);
ca29da43
NS
538 }
539 bbg_file_opened = 1;
540 }
159b3be1 541
ca29da43
NS
542 /* Announce function */
543 offset = gcov_write_tag (GCOV_TAG_FUNCTION);
6d70e6be 544 gcov_write_unsigned (current_function_funcdef_no + 1);
796621e8 545 gcov_write_unsigned (compute_checksum ());
ca29da43
NS
546 gcov_write_string (IDENTIFIER_POINTER
547 (DECL_ASSEMBLER_NAME (current_function_decl)));
a281759f
PB
548 gcov_write_string (xloc.file);
549 gcov_write_unsigned (xloc.line);
ca29da43
NS
550 gcov_write_length (offset);
551
552 bbg_function_announced = 1;
553 }
554 return !gcov_is_error ();
555}
556
557/* Finish coverage data for the current function. Verify no output
558 error has occurred. Save function coverage counts. */
559
560void
159b3be1 561coverage_end_function (void)
ca29da43
NS
562{
563 unsigned i;
159b3be1 564
ca29da43 565 if (bbg_file_opened > 1 && gcov_is_error ())
159b3be1 566 {
ca29da43
NS
567 warning ("error writing `%s'", bbg_file_name);
568 bbg_file_opened = -1;
569 }
cdb23767
NS
570
571 if (fn_ctr_mask)
572 {
573 struct function_list *item;
159b3be1 574
cdb23767 575 item = xmalloc (sizeof (struct function_list));
159b3be1 576
cdb23767
NS
577 *functions_tail = item;
578 functions_tail = &item->next;
159b3be1 579
cdb23767 580 item->next = 0;
6d70e6be 581 item->ident = current_function_funcdef_no + 1;
cdb23767
NS
582 item->checksum = compute_checksum ();
583 for (i = 0; i != GCOV_COUNTERS; i++)
584 {
585 item->n_ctrs[i] = fn_n_ctrs[i];
586 prg_n_ctrs[i] += fn_n_ctrs[i];
6d70e6be 587 fn_n_ctrs[i] = fn_b_ctrs[i] = 0;
cdb23767
NS
588 }
589 prg_ctr_mask |= fn_ctr_mask;
590 fn_ctr_mask = 0;
591 }
ca29da43
NS
592 bbg_function_announced = 0;
593}
594
cdb23767 595/* Creates the gcov_fn_info RECORD_TYPE. */
ca29da43 596
ca29da43 597static tree
159b3be1 598build_fn_info_type (unsigned int counters)
ca29da43 599{
ae2bcd98 600 tree type = lang_hooks.types.make_type (RECORD_TYPE);
ca29da43 601 tree field, fields;
cdb23767 602 tree array_type;
159b3be1 603
796621e8 604 /* ident */
9b514d25 605 fields = build_decl (FIELD_DECL, NULL_TREE, unsigned_intSI_type_node);
ca29da43 606
cdb23767 607 /* checksum */
9b514d25 608 field = build_decl (FIELD_DECL, NULL_TREE, unsigned_intSI_type_node);
ca29da43
NS
609 TREE_CHAIN (field) = fields;
610 fields = field;
611
cdb23767
NS
612 array_type = build_index_type (build_int_2 (counters - 1, 0));
613 array_type = build_array_type (unsigned_type_node, array_type);
159b3be1 614
ca29da43 615 /* counters */
cdb23767 616 field = build_decl (FIELD_DECL, NULL_TREE, array_type);
ca29da43
NS
617 TREE_CHAIN (field) = fields;
618 fields = field;
619
cdb23767
NS
620 finish_builtin_struct (type, "__gcov_fn_info", fields, NULL_TREE);
621
622 return type;
ca29da43
NS
623}
624
cdb23767
NS
625/* Creates a CONSTRUCTOR for a gcov_fn_info. FUNCTION is
626 the function being processed and TYPE is the gcov_fn_info
627 RECORD_TYPE. */
628
ca29da43 629static tree
159b3be1 630build_fn_info_value (const struct function_list *function, tree type)
ca29da43 631{
cdb23767
NS
632 tree value = NULL_TREE;
633 tree fields = TYPE_FIELDS (type);
cdb23767
NS
634 unsigned ix;
635 tree array_value = NULL_TREE;
159b3be1 636
796621e8 637 /* ident */
cdb23767 638 value = tree_cons (fields,
9b514d25 639 convert (unsigned_intSI_type_node,
796621e8 640 build_int_2 (function->ident, 0)),
ca29da43 641 value);
cdb23767 642 fields = TREE_CHAIN (fields);
159b3be1 643
cdb23767
NS
644 /* checksum */
645 value = tree_cons (fields,
9b514d25 646 convert (unsigned_intSI_type_node,
cdb23767 647 build_int_2 (function->checksum, 0)),
ca29da43 648 value);
cdb23767 649 fields = TREE_CHAIN (fields);
159b3be1 650
ca29da43 651 /* counters */
cdb23767
NS
652 for (ix = 0; ix != GCOV_COUNTERS; ix++)
653 if (prg_ctr_mask & (1 << ix))
654 {
655 tree counters = convert (unsigned_type_node,
656 build_int_2 (function->n_ctrs[ix], 0));
159b3be1 657
cdb23767
NS
658 array_value = tree_cons (NULL_TREE, counters, array_value);
659 }
159b3be1 660
cdb23767
NS
661 array_value = build_constructor (TREE_TYPE (fields), nreverse (array_value));
662 value = tree_cons (fields, array_value, value);
ca29da43 663
cdb23767 664 value = build_constructor (type, nreverse (value));
159b3be1 665
ca29da43
NS
666 return value;
667}
668
cdb23767
NS
669/* Creates the gcov_ctr_info RECORD_TYPE. */
670
ca29da43 671static tree
159b3be1 672build_ctr_info_type (void)
ca29da43 673{
ae2bcd98 674 tree type = lang_hooks.types.make_type (RECORD_TYPE);
cdb23767 675 tree field, fields = NULL_TREE;
9b514d25 676 tree gcov_ptr_type = build_pointer_type (GCOV_TYPE_NODE);
09780dfb 677 tree gcov_merge_fn_type;
9b514d25 678
cdb23767 679 /* counters */
9b514d25 680 field = build_decl (FIELD_DECL, NULL_TREE, unsigned_intSI_type_node);
ca29da43
NS
681 TREE_CHAIN (field) = fields;
682 fields = field;
683
cdb23767 684 /* values */
9b514d25 685 field = build_decl (FIELD_DECL, NULL_TREE, gcov_ptr_type);
ca29da43
NS
686 TREE_CHAIN (field) = fields;
687 fields = field;
688
09780dfb
ZD
689 /* merge */
690 gcov_merge_fn_type =
9b514d25
NS
691 build_function_type_list (void_type_node,
692 gcov_ptr_type, unsigned_type_node,
693 NULL_TREE);
09780dfb
ZD
694 field = build_decl (FIELD_DECL, NULL_TREE,
695 build_pointer_type (gcov_merge_fn_type));
696 TREE_CHAIN (field) = fields;
697 fields = field;
698
cdb23767 699 finish_builtin_struct (type, "__gcov_ctr_info", fields, NULL_TREE);
ca29da43 700
cdb23767 701 return type;
ca29da43
NS
702}
703
cdb23767
NS
704/* Creates a CONSTRUCTOR for a gcov_ctr_info. COUNTER is
705 the counter being processed and TYPE is the gcov_ctr_info
706 RECORD_TYPE. */
707
ca29da43 708static tree
159b3be1 709build_ctr_info_value (unsigned int counter, tree type)
ca29da43
NS
710{
711 tree value = NULL_TREE;
cdb23767 712 tree fields = TYPE_FIELDS (type);
09780dfb 713 tree fn;
ca29da43 714
cdb23767
NS
715 /* counters */
716 value = tree_cons (fields,
9b514d25 717 convert (unsigned_intSI_type_node,
cdb23767 718 build_int_2 (prg_n_ctrs[counter], 0)),
ca29da43 719 value);
cdb23767 720 fields = TREE_CHAIN (fields);
ca29da43 721
cdb23767 722 if (prg_n_ctrs[counter])
ca29da43 723 {
6de9cd9a 724 tree array_type;
159b3be1 725
cdb23767
NS
726 array_type = build_index_type (build_int_2 (prg_n_ctrs[counter] - 1, 0));
727 array_type = build_array_type (TREE_TYPE (TREE_TYPE (fields)),
728 array_type);
159b3be1 729
6de9cd9a
DN
730 TREE_TYPE (tree_ctr_tables[counter]) = array_type;
731 DECL_SIZE (tree_ctr_tables[counter]) = TYPE_SIZE (array_type);
732 DECL_SIZE_UNIT (tree_ctr_tables[counter]) = TYPE_SIZE_UNIT (array_type);
733 assemble_variable (tree_ctr_tables[counter], 0, 0, 0);
159b3be1 734
cdb23767 735 value = tree_cons (fields,
6de9cd9a
DN
736 build1 (ADDR_EXPR, TREE_TYPE (fields),
737 tree_ctr_tables[counter]),
cdb23767 738 value);
ca29da43
NS
739 }
740 else
cdb23767 741 value = tree_cons (fields, null_pointer_node, value);
09780dfb
ZD
742 fields = TREE_CHAIN (fields);
743
744 fn = build_decl (FUNCTION_DECL,
745 get_identifier (ctr_merge_functions[counter]),
746 TREE_TYPE (TREE_TYPE (fields)));
747 DECL_EXTERNAL (fn) = 1;
748 TREE_PUBLIC (fn) = 1;
749 DECL_ARTIFICIAL (fn) = 1;
750 TREE_NOTHROW (fn) = 1;
751 value = tree_cons (fields,
9b514d25 752 build1 (ADDR_EXPR, TREE_TYPE (fields), fn),
09780dfb 753 value);
ca29da43 754
cdb23767 755 value = build_constructor (type, nreverse (value));
159b3be1 756
ca29da43
NS
757 return value;
758}
759
cdb23767
NS
760/* Creates the gcov_info RECORD_TYPE and initializer for it. Returns a
761 CONSTRUCTOR. */
762
ca29da43 763static tree
159b3be1 764build_gcov_info (void)
ca29da43 765{
cdb23767
NS
766 unsigned n_ctr_types, ix;
767 tree type, const_type;
768 tree fn_info_type, fn_info_value = NULL_TREE;
769 tree fn_info_ptr_type;
770 tree ctr_info_type, ctr_info_ary_type, ctr_info_value = NULL_TREE;
771 tree field, fields = NULL_TREE;
772 tree value = NULL_TREE;
773 tree filename_string;
ca29da43
NS
774 char *filename;
775 int filename_len;
cdb23767
NS
776 unsigned n_fns;
777 const struct function_list *fn;
778 tree string_type;
159b3be1 779
cdb23767
NS
780 /* Count the number of active counters. */
781 for (n_ctr_types = 0, ix = 0; ix != GCOV_COUNTERS; ix++)
782 if (prg_ctr_mask & (1 << ix))
783 n_ctr_types++;
159b3be1 784
ae2bcd98 785 type = lang_hooks.types.make_type (RECORD_TYPE);
cdb23767 786 const_type = build_qualified_type (type, TYPE_QUAL_CONST);
159b3be1 787
cdb23767 788 /* Version ident */
9b514d25 789 field = build_decl (FIELD_DECL, NULL_TREE, unsigned_intSI_type_node);
ca29da43
NS
790 TREE_CHAIN (field) = fields;
791 fields = field;
9b514d25 792 value = tree_cons (field, convert (unsigned_intSI_type_node,
cdb23767 793 build_int_2 (GCOV_VERSION, 0)),
ca29da43 794 value);
159b3be1 795
ca29da43 796 /* next -- NULL */
cdb23767
NS
797 field = build_decl (FIELD_DECL, NULL_TREE, build_pointer_type (const_type));
798 TREE_CHAIN (field) = fields;
799 fields = field;
800 value = tree_cons (field, null_pointer_node, value);
159b3be1 801
dd486eb2
NS
802 /* stamp */
803 field = build_decl (FIELD_DECL, NULL_TREE, unsigned_intSI_type_node);
804 TREE_CHAIN (field) = fields;
805 fields = field;
806 value = tree_cons (field, convert (unsigned_intSI_type_node,
807 build_int_2 (local_tick, 0)),
808 value);
809
ca29da43 810 /* Filename */
cdb23767
NS
811 string_type = build_pointer_type (build_qualified_type (char_type_node,
812 TYPE_QUAL_CONST));
813 field = build_decl (FIELD_DECL, NULL_TREE, string_type);
814 TREE_CHAIN (field) = fields;
815 fields = field;
ca29da43
NS
816 filename = getpwd ();
817 filename = (filename && da_file_name[0] != '/'
818 ? concat (filename, "/", da_file_name, NULL)
819 : da_file_name);
820 filename_len = strlen (filename);
821 filename_string = build_string (filename_len + 1, filename);
822 if (filename != da_file_name)
823 free (filename);
824 TREE_TYPE (filename_string) =
825 build_array_type (char_type_node,
826 build_index_type (build_int_2 (filename_len, 0)));
cdb23767 827 value = tree_cons (field, build1 (ADDR_EXPR, string_type, filename_string),
ca29da43 828 value);
159b3be1 829
cdb23767
NS
830 /* Build the fn_info type and initializer. */
831 fn_info_type = build_fn_info_type (n_ctr_types);
832 fn_info_ptr_type = build_pointer_type (build_qualified_type
833 (fn_info_type, TYPE_QUAL_CONST));
834 for (fn = functions_head, n_fns = 0; fn; fn = fn->next, n_fns++)
835 fn_info_value = tree_cons (NULL_TREE,
836 build_fn_info_value (fn, fn_info_type),
837 fn_info_value);
838 if (n_fns)
ca29da43
NS
839 {
840 tree array_type;
841
cdb23767
NS
842 array_type = build_index_type (build_int_2 (n_fns - 1, 0));
843 array_type = build_array_type (fn_info_type, array_type);
159b3be1 844
cdb23767
NS
845 fn_info_value = build_constructor (array_type, nreverse (fn_info_value));
846 fn_info_value = build1 (ADDR_EXPR, fn_info_ptr_type, fn_info_value);
ca29da43
NS
847 }
848 else
cdb23767 849 fn_info_value = null_pointer_node;
159b3be1 850
cdb23767
NS
851 /* number of functions */
852 field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
853 TREE_CHAIN (field) = fields;
854 fields = field;
855 value = tree_cons (field,
856 convert (unsigned_type_node, build_int_2 (n_fns, 0)),
857 value);
159b3be1 858
cdb23767
NS
859 /* fn_info table */
860 field = build_decl (FIELD_DECL, NULL_TREE, fn_info_ptr_type);
861 TREE_CHAIN (field) = fields;
862 fields = field;
863 value = tree_cons (field, fn_info_value, value);
ca29da43 864
cdb23767
NS
865 /* counter_mask */
866 field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
867 TREE_CHAIN (field) = fields;
868 fields = field;
869 value = tree_cons (field,
ca29da43 870 convert (unsigned_type_node,
cdb23767 871 build_int_2 (prg_ctr_mask, 0)),
ca29da43 872 value);
159b3be1 873
cdb23767
NS
874 /* counters */
875 ctr_info_type = build_ctr_info_type ();
876 ctr_info_ary_type = build_index_type (build_int_2 (n_ctr_types, 0));
877 ctr_info_ary_type = build_array_type (ctr_info_type, ctr_info_ary_type);
878 for (ix = 0; ix != GCOV_COUNTERS; ix++)
879 if (prg_ctr_mask & (1 << ix))
880 ctr_info_value = tree_cons (NULL_TREE,
881 build_ctr_info_value (ix, ctr_info_type),
882 ctr_info_value);
883 ctr_info_value = build_constructor (ctr_info_ary_type,
884 nreverse (ctr_info_value));
885
886 field = build_decl (FIELD_DECL, NULL_TREE, ctr_info_ary_type);
887 TREE_CHAIN (field) = fields;
888 fields = field;
889 value = tree_cons (field, ctr_info_value, value);
159b3be1 890
cdb23767 891 finish_builtin_struct (type, "__gcov_info", fields, NULL_TREE);
ca29da43 892
cdb23767 893 value = build_constructor (type, nreverse (value));
159b3be1 894
ca29da43
NS
895 return value;
896}
897
cdb23767 898/* Write out the structure which libgcov uses to locate all the
ca29da43
NS
899 counters. The structures used here must match those defined in
900 gcov-io.h. Write out the constructor to call __gcov_init. */
901
902static void
159b3be1 903create_coverage (void)
ca29da43 904{
c9b9aa64
RH
905 tree gcov_info, gcov_init, body, t;
906 char name_buf[32];
ca29da43 907
6d70e6be 908 no_coverage = 1; /* Disable any further coverage. */
159b3be1 909
cdb23767 910 if (!prg_ctr_mask)
ca29da43 911 return;
159b3be1 912
c9b9aa64 913 t = build_gcov_info ();
ca29da43 914
c9b9aa64 915 gcov_info = build_decl (VAR_DECL, NULL_TREE, TREE_TYPE (t));
ca29da43 916 TREE_STATIC (gcov_info) = 1;
c9b9aa64
RH
917 ASM_GENERATE_INTERNAL_LABEL (name_buf, "LPBX", 0);
918 DECL_NAME (gcov_info) = get_identifier (name_buf);
919 DECL_INITIAL (gcov_info) = t;
159b3be1 920
ca29da43
NS
921 /* Build structure. */
922 assemble_variable (gcov_info, 0, 0, 0);
923
c9b9aa64
RH
924 /* Build a decl for __gcov_init. */
925 t = build_pointer_type (TREE_TYPE (gcov_info));
926 t = build_function_type_list (void_type_node, t, NULL);
927 t = build_decl (FUNCTION_DECL, get_identifier ("__gcov_init"), t);
928 TREE_PUBLIC (t) = 1;
929 DECL_EXTERNAL (t) = 1;
930 gcov_init = t;
931
932 /* Generate a call to __gcov_init(&gcov_info). */
933 body = NULL;
934 t = build_fold_addr_expr (gcov_info);
935 t = tree_cons (NULL, t, NULL);
936 t = build_function_call_expr (gcov_init, t);
937 append_to_statement_list (t, &body);
938
939 /* Generate a constructor to run it. */
35b6fdcf 940 cgraph_build_static_cdtor ('I', body, DEFAULT_INIT_PRIORITY);
ca29da43 941}
ca29da43
NS
942\f
943/* Perform file-level initialization. Read in data file, generate name
71c0e7fc 944 of graph file. */
ca29da43
NS
945
946void
159b3be1 947coverage_init (const char *filename)
ca29da43
NS
948{
949 int len = strlen (filename);
950
796621e8 951 /* Name of da file. */
703ad42b 952 da_file_name = xmalloc (len + strlen (GCOV_DATA_SUFFIX) + 1);
ca29da43
NS
953 strcpy (da_file_name, filename);
954 strcat (da_file_name, GCOV_DATA_SUFFIX);
159b3be1 955
796621e8 956 /* Name of bbg file. */
703ad42b 957 bbg_file_name = xmalloc (len + strlen (GCOV_NOTE_SUFFIX) + 1);
ca29da43 958 strcpy (bbg_file_name, filename);
160e2e4f 959 strcat (bbg_file_name, GCOV_NOTE_SUFFIX);
796621e8
NS
960
961 read_counts_file ();
ca29da43
NS
962}
963
964/* Performs file-level cleanup. Close graph file, generate coverage
965 variables and constructor. */
966
967void
159b3be1 968coverage_finish (void)
ca29da43
NS
969{
970 create_coverage ();
971 if (bbg_file_opened)
972 {
973 int error = gcov_close ();
159b3be1 974
ca29da43
NS
975 if (error)
976 unlink (bbg_file_name);
dd486eb2
NS
977 if (!local_tick)
978 /* Only remove the da file, if we cannot stamp it. If we can
979 stamp it, libgcov will DTRT. */
ca29da43
NS
980 unlink (da_file_name);
981 }
982}
983
ca29da43 984#include "gt-coverage.h"