1997-03-28 23:43:13 +01:00
|
|
|
|
/* Gcov.c: prepend line execution counts and branch probabilities to a
|
|
|
|
|
source file.
|
2000-02-26 07:23:30 +01:00
|
|
|
|
Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998,
|
2002-01-05 23:11:21 +01:00
|
|
|
|
1999, 2000, 2001, 2002 Free Software Foundation, Inc.
|
1997-03-28 23:43:13 +01:00
|
|
|
|
Contributed by James E. Wilson of Cygnus Support.
|
1997-12-20 12:31:54 +01:00
|
|
|
|
Mangled by Bob Manson of Cygnus Support.
|
1997-03-28 23:43:13 +01:00
|
|
|
|
|
|
|
|
|
Gcov is free software; you can redistribute it and/or modify
|
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
|
the Free Software Foundation; either version 2, or (at your option)
|
|
|
|
|
any later version.
|
|
|
|
|
|
|
|
|
|
Gcov is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
|
along with Gcov; see the file COPYING. If not, write to
|
1999-01-11 14:34:38 +01:00
|
|
|
|
the Free Software Foundation, 59 Temple Place - Suite 330,
|
|
|
|
|
Boston, MA 02111-1307, USA. */
|
1997-03-28 23:43:13 +01:00
|
|
|
|
|
|
|
|
|
/* ??? The code in final.c that produces the struct bb assumes that there is
|
|
|
|
|
no padding between the fields. This is not necessary true. The current
|
|
|
|
|
code can only be trusted if longs and pointers are the same size. */
|
|
|
|
|
|
|
|
|
|
/* ??? No need to print an execution count on every line, could just print
|
|
|
|
|
it on the first line of each block, and only print it on a subsequent
|
|
|
|
|
line in the same block if the count changes. */
|
|
|
|
|
|
|
|
|
|
/* ??? Print a list of the ten blocks with the highest execution counts,
|
|
|
|
|
and list the line numbers corresponding to those blocks. Also, perhaps
|
|
|
|
|
list the line numbers with the highest execution counts, only printing
|
|
|
|
|
the first if there are several which are all listed in the same block. */
|
|
|
|
|
|
|
|
|
|
/* ??? Should have an option to print the number of basic blocks, and the
|
|
|
|
|
percent of them that are covered. */
|
|
|
|
|
|
|
|
|
|
/* ??? Does not correctly handle the case where two .bb files refer to the
|
|
|
|
|
same included source file. For example, if one has a short file containing
|
|
|
|
|
only inline functions, which is then included in two other files, then
|
|
|
|
|
there will be two .bb files which refer to the include file, but there
|
|
|
|
|
is no way to get the total execution counts for the included file, can
|
|
|
|
|
only get execution counts for one or the other of the including files. */
|
|
|
|
|
|
1997-12-20 12:31:54 +01:00
|
|
|
|
#include "config.h"
|
More cutover to system.h:
* Makefile.in (cppalloc.o, cpperror.o, cppexp.o, cpphash.o,
cpplib.o, cppmain.o, fix-header.o, gcov.o, gen-protos.o,
gengenrtl.o, halfpic.o, hash.o, scan-decls.o, scan.o): Depend on
system.h.
* cpphash.c: Include config.h.
* cppalloc.c: Include system.h. Add parameters to various
function prototypes.
* cpperror.c: Likewise.
* cppexp.c: Likewise.
* cpphash.c: Likewise.
* cpplib.c: Likewise.
* cppmain.c: Likewise.
* fix-header.c: Likewise.
* gcov.c: Likewise.
* gen-protos.c: Likewise.
* gengenrtl.c: Likewise.
* halfpic.c: Likewise.
* hash.c: Likewise.
* scan-decls.c: Likewise.
* scan.c: Likewise.
From-SVN: r18911
1998-03-30 14:05:54 +02:00
|
|
|
|
#include "system.h"
|
1999-01-27 02:43:17 +01:00
|
|
|
|
#include "intl.h"
|
2001-11-01 22:48:49 +01:00
|
|
|
|
#include "version.h"
|
system.h: Always prototype abort.
1999-04-16 22:44 -0400 Zack Weinberg <zack@rabi.columbia.edu>
* system.h: Always prototype abort. Prototype fatal. Define
abort to call fatal, not fprintf/exit. Define a stub macro
for trim_filename.
* toplev.c: Define DIR_SEPARATOR. (trim_filename): New
function.
* toplev.h: Prototype trim_filename, and #undef system.h's stub.
* gcc.c, genattr.c, genattrtab.c, gencodes.c, genconfig.c,
genemit.c, genextract.c, genflags.c, genopinit.c, genoutput.c,
genpeep.c, genrecog.c: Make fatal non-static.
* gcov.c, gengenrtl.c, protoize.c: #undef abort after
including system.h.
* config/i386/dgux.h, config/m68k/xm-amix.h: Remove stale code
relating to abort.
From-SVN: r26511
1999-04-16 21:52:44 +02:00
|
|
|
|
#undef abort
|
1997-03-28 23:43:13 +01:00
|
|
|
|
|
2001-11-01 22:48:49 +01:00
|
|
|
|
#include <getopt.h>
|
|
|
|
|
|
regs.h (struct reg_info_def): Add freq field.
* regs.h (struct reg_info_def): Add freq field.
(REG_N_REFS): Update comment.
(REG_FREQ): New.
* regclass.c (scan_one_insn): Update REG_FREQ.
* flow.c (mark_set_1): Update REG_FREQ, make REG_N_SETS unweighted.
(attempt_auto_inc): Likewise.
(mark_used_reg): Likewise.
(try_pre_increment_1): Likewise.
* local-alloc.c (struct qty): Add freq field.
(alloc_qty): Set freq.
(update_equiv_regs): Set REG_FREQ.
(QTY_CMP_PRI): Use freq.
(combine_regs): Update qty->freq.
* global.c (struct allocno): Update comment for n_refs;
add freq field.
(local_reg_freq): New array.
(global_alloc): Update freq field;
allocate and initialize local_reg_freq.
(allocno_compare): Use freq field.
(find_reg): Likewise.
* reload1.c (count_pseudo): Use freq isntead of n_refs.
(count_spilled_pseudo): Likewise.
* tm.texi (GCOV_TYPE_SIZE): Document.
* basic-block.h (gcov_type): Define.
(struct edge_def): Use gcov_type for count field.
(struct basic_block_def): Likewise.
* defaults.h (GCOV_TYPE_SIZE): Define.
* final.c (end_final): Use GCOV_TYPE_SIZE.
* flow.c (dump_edge_info, dump_flow_info, dump_bb): Print count fields
using HOST_WIDEST_INT_PRINT_DEC.
* gcov-io.h (__fetch_gcov_type, __store_gcov_type, __read_gcov_type,
__write_gcov_type): New.
(store_long): Remove.
* gcov.c (gcov_type): Set default.
(struct adj_list): Use gcov_type for arc_count.
(bb_info): Use gcov_type for succ_count, pred_count and exec_count.
(create_program_flow_graph): Read arc_count properly.
(solve_program_flow_graph): 'total' is gcov_type.
(output_data): Line_counts is gcov_type, print it properly.
* libgcc2.c (struct bb): Counts is gcov_type.
(__bb_exit_func): Use __read_gcov_type and __write_gcov_type.
* profile.c (LONG_TYPE_SIZE, LONG_LONG_TYPE_SIZE): Set default.
(GCOV_TYPE_SIZE): Define.
(struct bb_info): succ_count and pred_count is gcov_type.
(compute_branch_probabilities): Use __read_gcov_type,
print read edges to the dump file.
(total): Is gcov_type.
(gen_edge_profiler): Use GCOV_TYPE_SIZE.
From-SVN: r43505
2001-06-22 19:18:23 +02:00
|
|
|
|
typedef HOST_WIDEST_INT gcov_type;
|
1997-03-28 23:43:13 +01:00
|
|
|
|
#include "gcov-io.h"
|
|
|
|
|
|
|
|
|
|
/* The .bb file format consists of several lists of 4-byte integers
|
|
|
|
|
which are the line numbers of each basic block in the file. Each
|
|
|
|
|
list is terminated by a zero. These lists correspond to the basic
|
|
|
|
|
blocks in the reconstructed program flow graph.
|
|
|
|
|
|
|
|
|
|
A line number of -1 indicates that a source file name (padded to a
|
|
|
|
|
long boundary) follows. The padded file name is followed by
|
|
|
|
|
another -1 to make it easy to scan past file names. A -2 indicates
|
|
|
|
|
that a function name (padded to a long boundary) follows; the name
|
|
|
|
|
is followed by another -2 to make it easy to scan past the function
|
|
|
|
|
name.
|
|
|
|
|
|
|
|
|
|
The .bbg file contains enough info to enable gcov to reconstruct the
|
|
|
|
|
program flow graph. The first word is the number of basic blocks,
|
|
|
|
|
the second word is the number of arcs, followed by the list of arcs
|
|
|
|
|
(source bb, dest bb pairs), then a -1, then the number of instrumented
|
|
|
|
|
arcs followed by the instrumented arcs, followed by another -1. This
|
|
|
|
|
is repeated for each function.
|
|
|
|
|
|
|
|
|
|
The .da file contains the execution count for each instrumented branch.
|
|
|
|
|
|
|
|
|
|
The .bb and .bbg files are created by giving GCC the -ftest-coverage option,
|
|
|
|
|
and the .da files are created when an executable compiled with
|
|
|
|
|
-fprofile-arcs is run. */
|
|
|
|
|
|
|
|
|
|
/* The functions in this file for creating and solution program flow graphs
|
|
|
|
|
are very similar to functions in the gcc source file profile.c. */
|
|
|
|
|
|
|
|
|
|
/* This is the size of the buffer used to read in source file lines. */
|
|
|
|
|
|
|
|
|
|
#define STRING_SIZE 200
|
|
|
|
|
|
|
|
|
|
/* One copy of this structure is created for each source file mentioned in the
|
|
|
|
|
.bb file. */
|
|
|
|
|
|
|
|
|
|
struct sourcefile
|
|
|
|
|
{
|
|
|
|
|
char *name;
|
|
|
|
|
int maxlineno;
|
|
|
|
|
struct sourcefile *next;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* This points to the head of the sourcefile structure list. */
|
|
|
|
|
|
|
|
|
|
struct sourcefile *sources;
|
|
|
|
|
|
|
|
|
|
/* One of these is dynamically created whenever we identify an arc in the
|
|
|
|
|
function. */
|
|
|
|
|
|
2002-08-07 01:18:01 +02:00
|
|
|
|
struct adj_list
|
|
|
|
|
{
|
1997-03-28 23:43:13 +01:00
|
|
|
|
int source;
|
|
|
|
|
int target;
|
regs.h (struct reg_info_def): Add freq field.
* regs.h (struct reg_info_def): Add freq field.
(REG_N_REFS): Update comment.
(REG_FREQ): New.
* regclass.c (scan_one_insn): Update REG_FREQ.
* flow.c (mark_set_1): Update REG_FREQ, make REG_N_SETS unweighted.
(attempt_auto_inc): Likewise.
(mark_used_reg): Likewise.
(try_pre_increment_1): Likewise.
* local-alloc.c (struct qty): Add freq field.
(alloc_qty): Set freq.
(update_equiv_regs): Set REG_FREQ.
(QTY_CMP_PRI): Use freq.
(combine_regs): Update qty->freq.
* global.c (struct allocno): Update comment for n_refs;
add freq field.
(local_reg_freq): New array.
(global_alloc): Update freq field;
allocate and initialize local_reg_freq.
(allocno_compare): Use freq field.
(find_reg): Likewise.
* reload1.c (count_pseudo): Use freq isntead of n_refs.
(count_spilled_pseudo): Likewise.
* tm.texi (GCOV_TYPE_SIZE): Document.
* basic-block.h (gcov_type): Define.
(struct edge_def): Use gcov_type for count field.
(struct basic_block_def): Likewise.
* defaults.h (GCOV_TYPE_SIZE): Define.
* final.c (end_final): Use GCOV_TYPE_SIZE.
* flow.c (dump_edge_info, dump_flow_info, dump_bb): Print count fields
using HOST_WIDEST_INT_PRINT_DEC.
* gcov-io.h (__fetch_gcov_type, __store_gcov_type, __read_gcov_type,
__write_gcov_type): New.
(store_long): Remove.
* gcov.c (gcov_type): Set default.
(struct adj_list): Use gcov_type for arc_count.
(bb_info): Use gcov_type for succ_count, pred_count and exec_count.
(create_program_flow_graph): Read arc_count properly.
(solve_program_flow_graph): 'total' is gcov_type.
(output_data): Line_counts is gcov_type, print it properly.
* libgcc2.c (struct bb): Counts is gcov_type.
(__bb_exit_func): Use __read_gcov_type and __write_gcov_type.
* profile.c (LONG_TYPE_SIZE, LONG_LONG_TYPE_SIZE): Set default.
(GCOV_TYPE_SIZE): Define.
(struct bb_info): succ_count and pred_count is gcov_type.
(compute_branch_probabilities): Use __read_gcov_type,
print read edges to the dump file.
(total): Is gcov_type.
(gen_edge_profiler): Use GCOV_TYPE_SIZE.
From-SVN: r43505
2001-06-22 19:18:23 +02:00
|
|
|
|
gcov_type arc_count;
|
1997-03-28 23:43:13 +01:00
|
|
|
|
unsigned int count_valid : 1;
|
|
|
|
|
unsigned int on_tree : 1;
|
|
|
|
|
unsigned int fake : 1;
|
|
|
|
|
unsigned int fall_through : 1;
|
|
|
|
|
#if 0
|
|
|
|
|
/* Not needed for gcov, but defined in profile.c. */
|
|
|
|
|
rtx branch_insn;
|
|
|
|
|
#endif
|
|
|
|
|
struct adj_list *pred_next;
|
|
|
|
|
struct adj_list *succ_next;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* Count the number of basic blocks, and create an array of these structures,
|
|
|
|
|
one for each bb in the function. */
|
|
|
|
|
|
2002-08-07 01:18:01 +02:00
|
|
|
|
struct bb_info
|
|
|
|
|
{
|
1997-03-28 23:43:13 +01:00
|
|
|
|
struct adj_list *succ;
|
|
|
|
|
struct adj_list *pred;
|
regs.h (struct reg_info_def): Add freq field.
* regs.h (struct reg_info_def): Add freq field.
(REG_N_REFS): Update comment.
(REG_FREQ): New.
* regclass.c (scan_one_insn): Update REG_FREQ.
* flow.c (mark_set_1): Update REG_FREQ, make REG_N_SETS unweighted.
(attempt_auto_inc): Likewise.
(mark_used_reg): Likewise.
(try_pre_increment_1): Likewise.
* local-alloc.c (struct qty): Add freq field.
(alloc_qty): Set freq.
(update_equiv_regs): Set REG_FREQ.
(QTY_CMP_PRI): Use freq.
(combine_regs): Update qty->freq.
* global.c (struct allocno): Update comment for n_refs;
add freq field.
(local_reg_freq): New array.
(global_alloc): Update freq field;
allocate and initialize local_reg_freq.
(allocno_compare): Use freq field.
(find_reg): Likewise.
* reload1.c (count_pseudo): Use freq isntead of n_refs.
(count_spilled_pseudo): Likewise.
* tm.texi (GCOV_TYPE_SIZE): Document.
* basic-block.h (gcov_type): Define.
(struct edge_def): Use gcov_type for count field.
(struct basic_block_def): Likewise.
* defaults.h (GCOV_TYPE_SIZE): Define.
* final.c (end_final): Use GCOV_TYPE_SIZE.
* flow.c (dump_edge_info, dump_flow_info, dump_bb): Print count fields
using HOST_WIDEST_INT_PRINT_DEC.
* gcov-io.h (__fetch_gcov_type, __store_gcov_type, __read_gcov_type,
__write_gcov_type): New.
(store_long): Remove.
* gcov.c (gcov_type): Set default.
(struct adj_list): Use gcov_type for arc_count.
(bb_info): Use gcov_type for succ_count, pred_count and exec_count.
(create_program_flow_graph): Read arc_count properly.
(solve_program_flow_graph): 'total' is gcov_type.
(output_data): Line_counts is gcov_type, print it properly.
* libgcc2.c (struct bb): Counts is gcov_type.
(__bb_exit_func): Use __read_gcov_type and __write_gcov_type.
* profile.c (LONG_TYPE_SIZE, LONG_LONG_TYPE_SIZE): Set default.
(GCOV_TYPE_SIZE): Define.
(struct bb_info): succ_count and pred_count is gcov_type.
(compute_branch_probabilities): Use __read_gcov_type,
print read edges to the dump file.
(total): Is gcov_type.
(gen_edge_profiler): Use GCOV_TYPE_SIZE.
From-SVN: r43505
2001-06-22 19:18:23 +02:00
|
|
|
|
gcov_type succ_count;
|
|
|
|
|
gcov_type pred_count;
|
|
|
|
|
gcov_type exec_count;
|
1997-03-28 23:43:13 +01:00
|
|
|
|
unsigned int count_valid : 1;
|
|
|
|
|
unsigned int on_tree : 1;
|
|
|
|
|
#if 0
|
|
|
|
|
/* Not needed for gcov, but defined in profile.c. */
|
|
|
|
|
rtx first_insn;
|
|
|
|
|
#endif
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* When outputting branch probabilities, one of these structures is created
|
|
|
|
|
for each branch/call. */
|
|
|
|
|
|
|
|
|
|
struct arcdata
|
|
|
|
|
{
|
2001-07-11 19:42:47 +02:00
|
|
|
|
gcov_type hits;
|
|
|
|
|
gcov_type total;
|
1997-03-28 23:43:13 +01:00
|
|
|
|
int call_insn;
|
|
|
|
|
struct arcdata *next;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* Used to save the list of bb_graphs, one per function. */
|
|
|
|
|
|
2002-08-07 01:18:01 +02:00
|
|
|
|
struct bb_info_list
|
|
|
|
|
{
|
1997-03-28 23:43:13 +01:00
|
|
|
|
/* Indexed by block number, holds the basic block graph for one function. */
|
|
|
|
|
struct bb_info *bb_graph;
|
|
|
|
|
int num_blocks;
|
|
|
|
|
struct bb_info_list *next;
|
|
|
|
|
};
|
|
|
|
|
|
2002-09-08 14:47:27 +02:00
|
|
|
|
/* Used to hold information about each line. */
|
2002-08-07 01:18:01 +02:00
|
|
|
|
struct line_info
|
|
|
|
|
{
|
|
|
|
|
gcov_type count; /* execution count */
|
2002-09-08 14:47:27 +02:00
|
|
|
|
struct arcdata *branches; /* list of branch probabilities for line. */
|
|
|
|
|
unsigned exists : 1; /* has code associated with it. */
|
2002-08-07 01:18:01 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct coverage
|
|
|
|
|
{
|
|
|
|
|
int lines;
|
|
|
|
|
int lines_executed;
|
|
|
|
|
|
|
|
|
|
int branches;
|
|
|
|
|
int branches_executed;
|
|
|
|
|
int branches_taken;
|
|
|
|
|
|
|
|
|
|
int calls;
|
|
|
|
|
int calls_executed;
|
|
|
|
|
|
|
|
|
|
char *name;
|
|
|
|
|
};
|
|
|
|
|
|
1997-03-28 23:43:13 +01:00
|
|
|
|
/* Holds a list of function basic block graphs. */
|
|
|
|
|
|
|
|
|
|
static struct bb_info_list *bb_graph_list = 0;
|
|
|
|
|
|
2002-09-08 14:47:27 +02:00
|
|
|
|
/* Modification time of data files. */
|
2002-08-04 19:06:10 +02:00
|
|
|
|
|
|
|
|
|
static time_t bb_file_time;
|
|
|
|
|
|
1997-03-28 23:43:13 +01:00
|
|
|
|
/* Name and file pointer of the input file for the basic block graph. */
|
|
|
|
|
|
|
|
|
|
static char *bbg_file_name;
|
|
|
|
|
static FILE *bbg_file;
|
|
|
|
|
|
|
|
|
|
/* Name and file pointer of the input file for the arc count data. */
|
|
|
|
|
|
|
|
|
|
static char *da_file_name;
|
|
|
|
|
static FILE *da_file;
|
|
|
|
|
|
|
|
|
|
/* Name and file pointer of the input file for the basic block line counts. */
|
|
|
|
|
|
|
|
|
|
static char *bb_file_name;
|
|
|
|
|
static FILE *bb_file;
|
|
|
|
|
|
|
|
|
|
/* Holds the entire contents of the bb_file read into memory. */
|
|
|
|
|
|
|
|
|
|
static char *bb_data;
|
|
|
|
|
|
|
|
|
|
/* Size of bb_data array in longs. */
|
|
|
|
|
|
|
|
|
|
static long bb_data_size;
|
|
|
|
|
|
|
|
|
|
/* Name of the file mentioned on the command line. */
|
|
|
|
|
|
|
|
|
|
static char *input_file_name = 0;
|
|
|
|
|
|
|
|
|
|
/* Output branch probabilities if true. */
|
|
|
|
|
|
|
|
|
|
static int output_branch_probs = 0;
|
|
|
|
|
|
|
|
|
|
/* Output a gcov file if this is true. This is on by default, and can
|
|
|
|
|
be turned off by the -n option. */
|
|
|
|
|
|
|
|
|
|
static int output_gcov_file = 1;
|
|
|
|
|
|
|
|
|
|
/* For included files, make the gcov output file name include the name of
|
|
|
|
|
the input source file. For example, if x.h is included in a.c, then the
|
|
|
|
|
output file name is a.c.x.h.gcov instead of x.h.gcov. This works only
|
|
|
|
|
when a single source file is specified. */
|
|
|
|
|
|
|
|
|
|
static int output_long_names = 0;
|
|
|
|
|
|
|
|
|
|
/* Output summary info for each function. */
|
|
|
|
|
|
|
|
|
|
static int output_function_summary = 0;
|
|
|
|
|
|
2002-08-04 19:06:10 +02:00
|
|
|
|
/* Object directory file prefix. This is the directory/file
|
2002-09-22 16:09:34 +02:00
|
|
|
|
where .bb and .bbg files are looked for, if nonzero. */
|
1997-03-28 23:43:13 +01:00
|
|
|
|
|
|
|
|
|
static char *object_directory = 0;
|
|
|
|
|
|
2002-08-04 19:06:10 +02:00
|
|
|
|
/* Preserve all pathname components. Needed when object files and
|
|
|
|
|
source files are in subdirectories. */
|
|
|
|
|
static int preserve_paths = 0;
|
|
|
|
|
|
1999-11-10 18:17:15 +01:00
|
|
|
|
/* Output the number of times a branch was taken as opposed to the percentage
|
|
|
|
|
of times it was taken. Turned on by the -c option */
|
2001-07-16 11:16:04 +02:00
|
|
|
|
|
1999-11-10 18:17:15 +01:00
|
|
|
|
static int output_branch_counts = 0;
|
|
|
|
|
|
1997-03-28 23:43:13 +01:00
|
|
|
|
/* Forward declarations. */
|
2000-01-14 18:14:43 +01:00
|
|
|
|
static void process_args PARAMS ((int, char **));
|
|
|
|
|
static void open_files PARAMS ((void));
|
|
|
|
|
static void read_files PARAMS ((void));
|
|
|
|
|
static void scan_for_source_files PARAMS ((void));
|
2002-08-07 01:18:01 +02:00
|
|
|
|
static void output_data PARAMS ((struct sourcefile *));
|
2001-11-01 22:48:49 +01:00
|
|
|
|
static void print_usage PARAMS ((int)) ATTRIBUTE_NORETURN;
|
|
|
|
|
static void print_version PARAMS ((void)) ATTRIBUTE_NORETURN;
|
2000-01-14 18:14:43 +01:00
|
|
|
|
static void init_arc PARAMS ((struct adj_list *, int, int, struct bb_info *));
|
|
|
|
|
static struct adj_list *reverse_arcs PARAMS ((struct adj_list *));
|
2002-05-09 14:54:19 +02:00
|
|
|
|
static gcov_type *read_profile PARAMS ((char *, long, int));
|
2000-01-14 18:14:43 +01:00
|
|
|
|
static void create_program_flow_graph PARAMS ((struct bb_info_list *));
|
|
|
|
|
static void solve_program_flow_graph PARAMS ((struct bb_info_list *));
|
2002-08-07 01:18:01 +02:00
|
|
|
|
static void accumulate_branch_counts PARAMS ((struct coverage *,
|
|
|
|
|
struct arcdata *));
|
|
|
|
|
static void calculate_branch_probs PARAMS ((struct bb_info *,
|
|
|
|
|
struct line_info *,
|
|
|
|
|
struct coverage *));
|
|
|
|
|
static void function_summary PARAMS ((struct coverage *, const char *));
|
|
|
|
|
static void init_line_info PARAMS ((struct line_info *,
|
|
|
|
|
struct coverage *, long));
|
|
|
|
|
static void output_line_info PARAMS ((FILE *, const struct line_info *,
|
|
|
|
|
const struct coverage *, long));
|
|
|
|
|
static char *make_gcov_file_name PARAMS ((char *));
|
|
|
|
|
static const char *format_hwint PARAMS ((HOST_WIDEST_INT, HOST_WIDEST_INT,
|
|
|
|
|
int));
|
2000-01-14 18:14:43 +01:00
|
|
|
|
|
|
|
|
|
extern int main PARAMS ((int, char **));
|
1997-03-28 23:43:13 +01:00
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
main (argc, argv)
|
|
|
|
|
int argc;
|
|
|
|
|
char **argv;
|
|
|
|
|
{
|
2002-08-07 01:18:01 +02:00
|
|
|
|
struct sourcefile *s_ptr;
|
|
|
|
|
|
2001-10-19 17:17:39 +02:00
|
|
|
|
gcc_init_libintl ();
|
1999-01-27 02:43:17 +01:00
|
|
|
|
|
1997-03-28 23:43:13 +01:00
|
|
|
|
process_args (argc, argv);
|
|
|
|
|
|
|
|
|
|
open_files ();
|
|
|
|
|
|
|
|
|
|
read_files ();
|
|
|
|
|
|
|
|
|
|
scan_for_source_files ();
|
|
|
|
|
|
2002-08-07 01:18:01 +02:00
|
|
|
|
for (s_ptr = sources; s_ptr; s_ptr = s_ptr->next)
|
|
|
|
|
output_data (s_ptr);
|
1997-03-28 23:43:13 +01:00
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2000-01-14 18:14:43 +01:00
|
|
|
|
static void fnotice PARAMS ((FILE *, const char *, ...)) ATTRIBUTE_PRINTF_2;
|
1999-01-27 02:43:17 +01:00
|
|
|
|
static void
|
2000-01-14 18:14:43 +01:00
|
|
|
|
fnotice VPARAMS ((FILE *file, const char *msgid, ...))
|
1999-01-27 02:43:17 +01:00
|
|
|
|
{
|
2001-08-27 08:48:43 +02:00
|
|
|
|
VA_OPEN (ap, msgid);
|
|
|
|
|
VA_FIXEDARG (ap, FILE *, file);
|
|
|
|
|
VA_FIXEDARG (ap, const char *, msgid);
|
1999-01-27 02:43:17 +01:00
|
|
|
|
|
1999-01-30 21:18:51 +01:00
|
|
|
|
vfprintf (file, _(msgid), ap);
|
2001-08-27 08:48:43 +02:00
|
|
|
|
VA_CLOSE (ap);
|
1999-01-27 02:43:17 +01:00
|
|
|
|
}
|
|
|
|
|
|
1997-03-28 23:43:13 +01:00
|
|
|
|
/* More 'friendly' abort that prints the line and file.
|
|
|
|
|
config.h can #define abort fancy_abort if you like that sort of thing. */
|
2000-01-14 18:14:43 +01:00
|
|
|
|
extern void fancy_abort PARAMS ((void)) ATTRIBUTE_NORETURN;
|
1997-03-28 23:43:13 +01:00
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
fancy_abort ()
|
|
|
|
|
{
|
[multiple changes]
Fri Oct 29 15:25:07 1999 Arnaud Charlet <charlet@ACT-Europe.FR>
* gcov.c (DIR_SEPARATOR): Provide default.
(output_data): Add test for MS-DOS format absolute filename.
(fancy_abort): Correct program name.
(open_files): Open all files in binary mode.
* libgcc2.c (__bb_exit_func): Likewise.
* profile.c (init_branch_prob): Specify binary when opening files.
* flags.h (flag_unwind_tables): New decl.
* toplev.c (flag_unwind_table): New definition.
(f_options): Add -funwind-tables.
(decode_g_option): Clarify warning when unknown -g option is given.
(rest_of_compilation): If inside an inlined external function,
pretend we are just being declared.
* dwarf2out.c (dwarf2out_do_frame): Check -funwind_tables.
(dwarf2out_frame_finish): Likewise.
Fri Oct 29 06:32:44 1999 Geoffrey Keating <geoffk@cygnus.com>
* flow.c (propagate_block): When the last reference to a label
before an ADDR_VEC is deleted because the reference is a dead
store, delete the ADDR_VEC.
Fri Oct 29 07:44:26 1999 Vasco Pedro <vp@di.fct.unl.pt>
* fold-const.c (merge_ranges): In not in0, but in1, handle
upper bounds equal like subset case.
Thu Oct 28 19:22:24 1999 Douglas Rupp <rupp@gnat.com>
* dbxout.c (dbxout_parms): Generate a second stabs line for parameters
passed in a register but moved to the stack.
Thu Oct 28 19:12:57 1999 Sam Tardieu <tardieu@act-europe.fr>
* gcc.c (pass_exit_codes, greatest_status): New variables.
(struct option_map): Add entry for "--pass-exit-codes".
(execute): Update greatest_status if error.
(display_help): Add documentation for -pass-exit-codes.
(process_command): Handle -pass-exit-codes.
(main): Look at pass_exit_codes and greatest_status on call to exit.
Thu Oct 28 18:06:50 1999 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
* reload.c (find_reloads): Refine test for no input reload
case to not includes reloads emitted after insn.
* function.c (find_temp_slots_from_address): Handle sum involving
a register that points to a temp slot.
(update_temp_slot_address): Make recursive call if both old and
new are PLUS with a common operand.
* calls.c (expand_call): Mark temp slot for result as having
address taken.
* rtlanal.c (reg_referenced_p, case IF_THEN_ELSE): New case.
* gcc.c (process_command): Add standard_exec_prefix with "GCC"
component as well as "BINUTILS".
* integrate.h (copy_rtx_and_substitute): New arg, FOR_LHS.
* integrate.c (copy_rtx_and_substitute): Likewise.
(expand_inline_function, integrate_parm_decls, integrate_decl_tree):
All callers changed.
* unroll.c (inital_reg_note_copy, copy_loop_body): Likewise.
* dbxout.c (dbxout_type, case INTEGER_TYPE_NODE): If can use
gdb extensions, write size of type; also be more consistent
in using references when this is a subtype.
* pa.md (extv, extzv, insv): Use define_expand to reject constant
that is out of range.
* loop.c (unknown_constant_address_altered): New variable.
(prescan_loop): Initialize it.
(note_addr_stored): Set it for RTX_UNCHANGING_P MEM.
(invariant_p, case MEM): Remove handling for volatile and readony;
check new variable if readonly.
(check_dbra_loop): Chdeck unknown_constant_address_altered.
* cse.c (canon_hash, case MEM): Do not record if BLKmode.
(addr_affects_sp_p): Removed from note_mem_written and only
define #ifdef AUTO_INC_DEC.
* alpha.c (input_operand, case ADDRESSOF): Treat as REG.
* regclass.c (record_reg_classes): Properly handle register move
directions.
* varasm.c (initializer_constant_valid_p, case MINUS_EXPR):
Don't think valid if both operands are invalid.
(struct constant_descriptor): New field RTL.
(mark_const_hash_entry): Mark it.
(record_constant{,_rtx}): Initialize it.
(output_constant_def): Allocate RTL in permanent obstack and
save in table.
({record,compare}_constant_1): Modes must match for
CONSTRUCTOR of ARRAY_TYPE.
* c-common.h (initializer_constant_valid_p): Delete decl from here.
* output.h (initializer_constant_valid_p): Move decl to here.
* c-common.c (initializer_constant_valid_p): Delete function from here.
* varasm.c (initializer_constant_valid_p): Move function to here.
* tree.h (STRIP_SIGN_NOPS): New macro.
* fold-const.c (optimize_minmax_comparison): New function.
(invert_truthvalue, case WITH_RECORD_EXPR): New case.
(fold): Use STRIP_SIGN_NOPS instead of STRIP_TYPE_NOPS.
(fold, case EQ_EXPR): Call optimize_minmax_comparison and add
cases with ABS_EXPR, NEGATE_EXPR, PLUS_EXPR, MINUS_EXPR, and
widening conversions.
(fold, case LE_EXPR): Rework changing unsigned to signed comparisons
to look at size of mode, not precision of type; also add missing cases.
(optimize_bit_field_compare, decode_field_reference): Don't try to
optimize COMPONENT_REF of a PLACEHOLDER_EXPR.
* dwarf2out.c (ctype.h): Include.
(dwarf2out_set_demangle_name_func): New function.
(size_of_line_info): Deleted.
(output_line_info): Compute size of line info table from difference
of labels.
(base_type_die, add_name_attribute): Call demangle function, if any.
(field_byte_offset): Use bits per word for variable length fields.
(gen_array_type_die): Add array name.
(gen_subprogram_die): Ignore DECL_INLINE if -fno-inline.
(dwarf2out_add_library_unit_info): New function.
* explow.c (set_stack_check_libfunc): New function.
(stack_check_libfunc): New static variable.
(probe_stack_range): Allow front-end to set up a libfunc to call.
* combine.c (simplify_comparison): When making comparison in wider
mode, check for having commuted an AND and a SUBREG.
(contains_muldiv): New function.
(try_combine): Call it when dividing a PARALLEL.
(simplify_rtx, case TRUNCATE): Don't remove for umulsi3_highpart.
(simplify_comparison, case ASHIFTRT): Recognize sign-extension of
a PLUS.
(record_value_for_reg): If TEM is a binary operation with two CLOBBERs,
use one of the CLOBBERs instead.
(if_then_else_cond): If comparing against zero, just return thing
being compared.
* optabs.c (expand_abs): If machine has MAX, ABS (x) is MAX (x, -x).
Don't generate shifts and subtract if have conditional arithmetic.
* rtl.h (delete_barrier): New declaration.
* jump.c (jump_optimize): Set up to handle conditional call.
In conditional arithmetic case, handle CALL_INSN followed by a BARRIER.
(delete_barrier): New function.
* rtl.c (read_rtx): Call fatal if bad RTL code; check for bad mode.
* recog.c (nonmemory_operand): Accept ADDRESSOF.
* tree.c (build_type_attribute_variant): Push to obstack of
ttype around type_hash_canon call.
* expr.c (placeholder_list): Move decl to file scope.
(expand_expr): Don't force access to volatile just because its
address is taken.
If ignoring reference operations, just expand the operands.
(expand_expr, case COMPONENT_REF): Propagate
EXPAND_CONST_ADDRESS to recursive call when expanding inner.
Refine test for using bitfield operations vs pointer punning.
(expand_expr, case CONVERT_EXPR): If converting to
BLKmode UNION_TYPE from BLKmode, just return inner object.
Use proper mode in store_field call.
Properly set sizes of object to store and total size in store_field
call for convert to union.
(expand_expr, case ARRAY_REF): If OP0 is in a register, put it in
memory (like for ADDR_EXPR). Also, don't put constant in register if
we'll want it in memory.
(readonly_fields_p): New function.
(expand_expr, case INDIRECT_REF): Call it if LHS.
(expand_assignment): Handle a RESULT_DECL where
DECL_RTL is a PARALLEL.
(do_jump, case WITH_RECORD_EXPR): New case.
(get_inner_reference): Always go inside a CONVERT_EXPR
and NOP_EXPR if both modes are the same.
(store_field): Use bitfield operations if size of bitsize is not same
as size of RHS's type.
Check for bitpos not a multiple of alignment in BLKmode case.
Do block move in largest possible alignment.
(store_constructor): Set BITSIZE to -1 for variable size and properly
in case of array of BLKmode.
(expand_expr_unaligned): New function.
(do_compare_and_jump): Call it.
* mips/iris5.h (SWITCHES_NEED_SPACES): New macro.
* collect2.c (main): Only allow -ofoo if SWITCHES_NEED_SPACES
does not include 'o'.
* function.c (instantiate_virtual_regs_1, case SET): Handle case where
both SET_DEST and SET_SRC reference a virtual register.
(gen_mem_addressof): Copy RTX_UNCHANGING_P from new REG to old REG.
* integrate.c (expand_inline_function): Handle case of setting
virtual stack vars register (from built in setjmp); when parameter
lives in memory, expand virtual_{stack_vars,incoming_args}_rtx early.
(subst_constant): Add new parm, MEMONLY.
(expand_inline_function, integrate_parm_decls): Pass new parm.
(integrate_decl_tree): Likewise.
(copy_rtx_and_substitute, case MEM): Do copy RTX_UNCHANGING_P.
(try_constants): Call subst_constants twice, with MEMONLY 0 and 1.
(copy_rtx_and_substitute, case SET): Add explicit calls to
copy_rtx_and_substitute for both sides.
* stmt.c (expand_asm_operands): Don't use TREE_STRING_LENGTH for
constraints.
(pushcase{,_range}): Convert to NOMINAL_TYPE after checking for
within INDEX_TYPE, instead of before.
(fixup_gotos): Use f->target_rtl, not the next insn,
since latter may be from a later fixup.
(expand_value_return): Correctly convert VAL when promoting function
return; support RETURN_REG being a PARALLEL.
(expand_return): When checking for result in regs and having
cleanup, consider PARALLEL in DECL_RTL as being in regs.
From-SVN: r30299
1999-11-01 02:11:22 +01:00
|
|
|
|
fnotice (stderr, "Internal gcov abort.\n");
|
1997-03-28 23:43:13 +01:00
|
|
|
|
exit (FATAL_EXIT_CODE);
|
|
|
|
|
}
|
|
|
|
|
|
2001-11-01 22:48:49 +01:00
|
|
|
|
/* Print a usage message and exit. If ERROR_P is nonzero, this is an error,
|
|
|
|
|
otherwise the output of --help. */
|
1997-03-28 23:43:13 +01:00
|
|
|
|
|
|
|
|
|
static void
|
2001-11-01 22:48:49 +01:00
|
|
|
|
print_usage (error_p)
|
|
|
|
|
int error_p;
|
1997-03-28 23:43:13 +01:00
|
|
|
|
{
|
2001-11-01 22:48:49 +01:00
|
|
|
|
FILE *file = error_p ? stderr : stdout;
|
|
|
|
|
int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
|
|
|
|
|
fnotice (file, "Usage: gcov [OPTION]... SOURCEFILE\n\n");
|
|
|
|
|
fnotice (file, "Print code coverage information.\n\n");
|
|
|
|
|
fnotice (file, " -h, --help Print this help, then exit\n");
|
|
|
|
|
fnotice (file, " -v, --version Print version number, then exit\n");
|
|
|
|
|
fnotice (file, " -b, --branch-probabilities Include branch probabilities in output\n");
|
|
|
|
|
fnotice (file, " -c, --branch-counts Given counts of branches taken\n\
|
|
|
|
|
rather than percentages\n");
|
|
|
|
|
fnotice (file, " -n, --no-output Do not create an output file\n");
|
|
|
|
|
fnotice (file, " -l, --long-file-names Use long output file names for included\n\
|
|
|
|
|
source files\n");
|
|
|
|
|
fnotice (file, " -f, --function-summaries Output summaries for each function\n");
|
2002-08-04 19:06:10 +02:00
|
|
|
|
fnotice (file, " -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
|
|
|
|
|
fnotice (file, " -p, --preserve-paths Preserve all pathname components\n");
|
2001-11-01 22:48:49 +01:00
|
|
|
|
fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
|
2002-10-08 21:45:17 +02:00
|
|
|
|
bug_report_url);
|
2001-11-01 22:48:49 +01:00
|
|
|
|
exit (status);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Print version information and exit. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
print_version ()
|
|
|
|
|
{
|
|
|
|
|
fnotice (stdout, "gcov (GCC) %s\n", version_string);
|
|
|
|
|
fnotice (stdout, "Copyright (C) 2001 Free Software Foundation, Inc.\n");
|
|
|
|
|
fnotice (stdout,
|
|
|
|
|
"This is free software; see the source for copying conditions. There is NO\n\
|
|
|
|
|
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
|
|
|
|
|
exit (SUCCESS_EXIT_CODE);
|
1997-03-28 23:43:13 +01:00
|
|
|
|
}
|
|
|
|
|
|
2001-11-01 22:48:49 +01:00
|
|
|
|
static const struct option options[] =
|
|
|
|
|
{
|
|
|
|
|
{ "help", no_argument, NULL, 'h' },
|
|
|
|
|
{ "version", no_argument, NULL, 'v' },
|
|
|
|
|
{ "branch-probabilities", no_argument, NULL, 'b' },
|
|
|
|
|
{ "branch-counts", no_argument, NULL, 'c' },
|
|
|
|
|
{ "no-output", no_argument, NULL, 'n' },
|
|
|
|
|
{ "long-file-names", no_argument, NULL, 'l' },
|
|
|
|
|
{ "function-summaries", no_argument, NULL, 'f' },
|
2002-08-04 19:06:10 +02:00
|
|
|
|
{ "preserve-paths", no_argument, NULL, 'p' },
|
|
|
|
|
{ "object-directory", required_argument, NULL, 'o' },
|
|
|
|
|
{ "object-file", required_argument, NULL, 'o' },
|
2001-11-01 22:48:49 +01:00
|
|
|
|
};
|
|
|
|
|
|
1997-03-28 23:43:13 +01:00
|
|
|
|
/* Parse the command line. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
process_args (argc, argv)
|
|
|
|
|
int argc;
|
|
|
|
|
char **argv;
|
|
|
|
|
{
|
2001-11-01 22:48:49 +01:00
|
|
|
|
int opt;
|
1997-03-28 23:43:13 +01:00
|
|
|
|
|
2002-08-04 19:06:10 +02:00
|
|
|
|
while ((opt = getopt_long (argc, argv, "hvbclnfo:p", options, NULL)) != -1)
|
1997-03-28 23:43:13 +01:00
|
|
|
|
{
|
2001-11-01 22:48:49 +01:00
|
|
|
|
switch (opt)
|
1997-03-28 23:43:13 +01:00
|
|
|
|
{
|
2001-11-01 22:48:49 +01:00
|
|
|
|
case 'h':
|
|
|
|
|
print_usage (false);
|
|
|
|
|
/* print_usage will exit. */
|
|
|
|
|
case 'v':
|
|
|
|
|
print_version ();
|
|
|
|
|
/* print_version will exit. */
|
|
|
|
|
case 'b':
|
|
|
|
|
output_branch_probs = 1;
|
|
|
|
|
break;
|
|
|
|
|
case 'c':
|
|
|
|
|
output_branch_counts = 1;
|
|
|
|
|
break;
|
|
|
|
|
case 'n':
|
|
|
|
|
output_gcov_file = 0;
|
|
|
|
|
break;
|
|
|
|
|
case 'l':
|
|
|
|
|
output_long_names = 1;
|
|
|
|
|
break;
|
|
|
|
|
case 'f':
|
|
|
|
|
output_function_summary = 1;
|
|
|
|
|
break;
|
|
|
|
|
case 'o':
|
|
|
|
|
object_directory = optarg;
|
|
|
|
|
break;
|
2002-08-04 19:06:10 +02:00
|
|
|
|
case 'p':
|
|
|
|
|
preserve_paths = 1;
|
|
|
|
|
break;
|
2001-11-01 22:48:49 +01:00
|
|
|
|
default:
|
|
|
|
|
print_usage (true);
|
|
|
|
|
/* print_usage will exit. */
|
1997-03-28 23:43:13 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2001-11-01 22:48:49 +01:00
|
|
|
|
if (optind != argc - 1)
|
|
|
|
|
print_usage (true);
|
|
|
|
|
|
|
|
|
|
input_file_name = argv[optind];
|
1997-03-28 23:43:13 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2002-08-04 19:06:10 +02:00
|
|
|
|
/* Find and open the .bb, .da, and .bbg files. If OBJECT_DIRECTORY is
|
|
|
|
|
not specified, these are looked for in the current directory, and
|
|
|
|
|
named from the basename of the input_file_name sans extension. If
|
|
|
|
|
OBJECT_DIRECTORY is specified and is a directory, the files are in
|
|
|
|
|
that directory, but named from the basename of the input_file_name,
|
|
|
|
|
sans extension. Otherwise OBJECT_DIRECTORY is taken to be the name
|
|
|
|
|
of the object *file*, and the data files are named from that. */
|
1997-03-28 23:43:13 +01:00
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
open_files ()
|
|
|
|
|
{
|
|
|
|
|
char *cptr;
|
2002-08-04 19:06:10 +02:00
|
|
|
|
char *name;
|
|
|
|
|
int length = strlen (input_file_name);
|
|
|
|
|
int base;
|
|
|
|
|
|
|
|
|
|
if (object_directory && object_directory[0])
|
1997-03-28 23:43:13 +01:00
|
|
|
|
{
|
2002-08-04 19:06:10 +02:00
|
|
|
|
struct stat status;
|
|
|
|
|
|
|
|
|
|
length += strlen (object_directory) + 2;
|
|
|
|
|
name = xmalloc (length);
|
|
|
|
|
name[0] = 0;
|
|
|
|
|
|
|
|
|
|
base = !stat (object_directory, &status) && S_ISDIR (status.st_mode);
|
|
|
|
|
strcat (name, object_directory);
|
|
|
|
|
if (base && name[strlen (name) - 1] != '/')
|
|
|
|
|
strcat (name, "/");
|
1997-03-28 23:43:13 +01:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2002-08-04 19:06:10 +02:00
|
|
|
|
name = xmalloc (length + 1);
|
|
|
|
|
name[0] = 0;
|
|
|
|
|
base = 1;
|
1997-03-28 23:43:13 +01:00
|
|
|
|
}
|
2002-08-04 19:06:10 +02:00
|
|
|
|
|
|
|
|
|
if (base)
|
|
|
|
|
{
|
|
|
|
|
/* Append source file name */
|
|
|
|
|
cptr = strrchr (input_file_name, '/');
|
|
|
|
|
cptr = cptr ? cptr + 1 : input_file_name;
|
1997-03-28 23:43:13 +01:00
|
|
|
|
|
2002-08-04 19:06:10 +02:00
|
|
|
|
strcat (name, cptr);
|
|
|
|
|
}
|
2002-09-08 14:47:27 +02:00
|
|
|
|
/* Remove the extension. */
|
2002-08-04 19:06:10 +02:00
|
|
|
|
cptr = strrchr (name, '.');
|
1997-03-28 23:43:13 +01:00
|
|
|
|
if (cptr)
|
2002-08-04 19:06:10 +02:00
|
|
|
|
*cptr = 0;
|
|
|
|
|
|
|
|
|
|
length = strlen (name);
|
|
|
|
|
da_file_name = xmalloc (length + 4);
|
|
|
|
|
bb_file_name = xmalloc (length + 4);
|
|
|
|
|
bbg_file_name = xmalloc (length + 5);
|
|
|
|
|
|
|
|
|
|
strcpy (da_file_name, name);
|
|
|
|
|
strcpy (bb_file_name, name);
|
|
|
|
|
strcpy (bbg_file_name, name);
|
|
|
|
|
strcpy (da_file_name + length, ".da");
|
|
|
|
|
strcpy (bb_file_name + length, ".bb");
|
|
|
|
|
strcpy (bbg_file_name + length, ".bbg");
|
1997-03-28 23:43:13 +01:00
|
|
|
|
|
[multiple changes]
Fri Oct 29 15:25:07 1999 Arnaud Charlet <charlet@ACT-Europe.FR>
* gcov.c (DIR_SEPARATOR): Provide default.
(output_data): Add test for MS-DOS format absolute filename.
(fancy_abort): Correct program name.
(open_files): Open all files in binary mode.
* libgcc2.c (__bb_exit_func): Likewise.
* profile.c (init_branch_prob): Specify binary when opening files.
* flags.h (flag_unwind_tables): New decl.
* toplev.c (flag_unwind_table): New definition.
(f_options): Add -funwind-tables.
(decode_g_option): Clarify warning when unknown -g option is given.
(rest_of_compilation): If inside an inlined external function,
pretend we are just being declared.
* dwarf2out.c (dwarf2out_do_frame): Check -funwind_tables.
(dwarf2out_frame_finish): Likewise.
Fri Oct 29 06:32:44 1999 Geoffrey Keating <geoffk@cygnus.com>
* flow.c (propagate_block): When the last reference to a label
before an ADDR_VEC is deleted because the reference is a dead
store, delete the ADDR_VEC.
Fri Oct 29 07:44:26 1999 Vasco Pedro <vp@di.fct.unl.pt>
* fold-const.c (merge_ranges): In not in0, but in1, handle
upper bounds equal like subset case.
Thu Oct 28 19:22:24 1999 Douglas Rupp <rupp@gnat.com>
* dbxout.c (dbxout_parms): Generate a second stabs line for parameters
passed in a register but moved to the stack.
Thu Oct 28 19:12:57 1999 Sam Tardieu <tardieu@act-europe.fr>
* gcc.c (pass_exit_codes, greatest_status): New variables.
(struct option_map): Add entry for "--pass-exit-codes".
(execute): Update greatest_status if error.
(display_help): Add documentation for -pass-exit-codes.
(process_command): Handle -pass-exit-codes.
(main): Look at pass_exit_codes and greatest_status on call to exit.
Thu Oct 28 18:06:50 1999 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
* reload.c (find_reloads): Refine test for no input reload
case to not includes reloads emitted after insn.
* function.c (find_temp_slots_from_address): Handle sum involving
a register that points to a temp slot.
(update_temp_slot_address): Make recursive call if both old and
new are PLUS with a common operand.
* calls.c (expand_call): Mark temp slot for result as having
address taken.
* rtlanal.c (reg_referenced_p, case IF_THEN_ELSE): New case.
* gcc.c (process_command): Add standard_exec_prefix with "GCC"
component as well as "BINUTILS".
* integrate.h (copy_rtx_and_substitute): New arg, FOR_LHS.
* integrate.c (copy_rtx_and_substitute): Likewise.
(expand_inline_function, integrate_parm_decls, integrate_decl_tree):
All callers changed.
* unroll.c (inital_reg_note_copy, copy_loop_body): Likewise.
* dbxout.c (dbxout_type, case INTEGER_TYPE_NODE): If can use
gdb extensions, write size of type; also be more consistent
in using references when this is a subtype.
* pa.md (extv, extzv, insv): Use define_expand to reject constant
that is out of range.
* loop.c (unknown_constant_address_altered): New variable.
(prescan_loop): Initialize it.
(note_addr_stored): Set it for RTX_UNCHANGING_P MEM.
(invariant_p, case MEM): Remove handling for volatile and readony;
check new variable if readonly.
(check_dbra_loop): Chdeck unknown_constant_address_altered.
* cse.c (canon_hash, case MEM): Do not record if BLKmode.
(addr_affects_sp_p): Removed from note_mem_written and only
define #ifdef AUTO_INC_DEC.
* alpha.c (input_operand, case ADDRESSOF): Treat as REG.
* regclass.c (record_reg_classes): Properly handle register move
directions.
* varasm.c (initializer_constant_valid_p, case MINUS_EXPR):
Don't think valid if both operands are invalid.
(struct constant_descriptor): New field RTL.
(mark_const_hash_entry): Mark it.
(record_constant{,_rtx}): Initialize it.
(output_constant_def): Allocate RTL in permanent obstack and
save in table.
({record,compare}_constant_1): Modes must match for
CONSTRUCTOR of ARRAY_TYPE.
* c-common.h (initializer_constant_valid_p): Delete decl from here.
* output.h (initializer_constant_valid_p): Move decl to here.
* c-common.c (initializer_constant_valid_p): Delete function from here.
* varasm.c (initializer_constant_valid_p): Move function to here.
* tree.h (STRIP_SIGN_NOPS): New macro.
* fold-const.c (optimize_minmax_comparison): New function.
(invert_truthvalue, case WITH_RECORD_EXPR): New case.
(fold): Use STRIP_SIGN_NOPS instead of STRIP_TYPE_NOPS.
(fold, case EQ_EXPR): Call optimize_minmax_comparison and add
cases with ABS_EXPR, NEGATE_EXPR, PLUS_EXPR, MINUS_EXPR, and
widening conversions.
(fold, case LE_EXPR): Rework changing unsigned to signed comparisons
to look at size of mode, not precision of type; also add missing cases.
(optimize_bit_field_compare, decode_field_reference): Don't try to
optimize COMPONENT_REF of a PLACEHOLDER_EXPR.
* dwarf2out.c (ctype.h): Include.
(dwarf2out_set_demangle_name_func): New function.
(size_of_line_info): Deleted.
(output_line_info): Compute size of line info table from difference
of labels.
(base_type_die, add_name_attribute): Call demangle function, if any.
(field_byte_offset): Use bits per word for variable length fields.
(gen_array_type_die): Add array name.
(gen_subprogram_die): Ignore DECL_INLINE if -fno-inline.
(dwarf2out_add_library_unit_info): New function.
* explow.c (set_stack_check_libfunc): New function.
(stack_check_libfunc): New static variable.
(probe_stack_range): Allow front-end to set up a libfunc to call.
* combine.c (simplify_comparison): When making comparison in wider
mode, check for having commuted an AND and a SUBREG.
(contains_muldiv): New function.
(try_combine): Call it when dividing a PARALLEL.
(simplify_rtx, case TRUNCATE): Don't remove for umulsi3_highpart.
(simplify_comparison, case ASHIFTRT): Recognize sign-extension of
a PLUS.
(record_value_for_reg): If TEM is a binary operation with two CLOBBERs,
use one of the CLOBBERs instead.
(if_then_else_cond): If comparing against zero, just return thing
being compared.
* optabs.c (expand_abs): If machine has MAX, ABS (x) is MAX (x, -x).
Don't generate shifts and subtract if have conditional arithmetic.
* rtl.h (delete_barrier): New declaration.
* jump.c (jump_optimize): Set up to handle conditional call.
In conditional arithmetic case, handle CALL_INSN followed by a BARRIER.
(delete_barrier): New function.
* rtl.c (read_rtx): Call fatal if bad RTL code; check for bad mode.
* recog.c (nonmemory_operand): Accept ADDRESSOF.
* tree.c (build_type_attribute_variant): Push to obstack of
ttype around type_hash_canon call.
* expr.c (placeholder_list): Move decl to file scope.
(expand_expr): Don't force access to volatile just because its
address is taken.
If ignoring reference operations, just expand the operands.
(expand_expr, case COMPONENT_REF): Propagate
EXPAND_CONST_ADDRESS to recursive call when expanding inner.
Refine test for using bitfield operations vs pointer punning.
(expand_expr, case CONVERT_EXPR): If converting to
BLKmode UNION_TYPE from BLKmode, just return inner object.
Use proper mode in store_field call.
Properly set sizes of object to store and total size in store_field
call for convert to union.
(expand_expr, case ARRAY_REF): If OP0 is in a register, put it in
memory (like for ADDR_EXPR). Also, don't put constant in register if
we'll want it in memory.
(readonly_fields_p): New function.
(expand_expr, case INDIRECT_REF): Call it if LHS.
(expand_assignment): Handle a RESULT_DECL where
DECL_RTL is a PARALLEL.
(do_jump, case WITH_RECORD_EXPR): New case.
(get_inner_reference): Always go inside a CONVERT_EXPR
and NOP_EXPR if both modes are the same.
(store_field): Use bitfield operations if size of bitsize is not same
as size of RHS's type.
Check for bitpos not a multiple of alignment in BLKmode case.
Do block move in largest possible alignment.
(store_constructor): Set BITSIZE to -1 for variable size and properly
in case of array of BLKmode.
(expand_expr_unaligned): New function.
(do_compare_and_jump): Call it.
* mips/iris5.h (SWITCHES_NEED_SPACES): New macro.
* collect2.c (main): Only allow -ofoo if SWITCHES_NEED_SPACES
does not include 'o'.
* function.c (instantiate_virtual_regs_1, case SET): Handle case where
both SET_DEST and SET_SRC reference a virtual register.
(gen_mem_addressof): Copy RTX_UNCHANGING_P from new REG to old REG.
* integrate.c (expand_inline_function): Handle case of setting
virtual stack vars register (from built in setjmp); when parameter
lives in memory, expand virtual_{stack_vars,incoming_args}_rtx early.
(subst_constant): Add new parm, MEMONLY.
(expand_inline_function, integrate_parm_decls): Pass new parm.
(integrate_decl_tree): Likewise.
(copy_rtx_and_substitute, case MEM): Do copy RTX_UNCHANGING_P.
(try_constants): Call subst_constants twice, with MEMONLY 0 and 1.
(copy_rtx_and_substitute, case SET): Add explicit calls to
copy_rtx_and_substitute for both sides.
* stmt.c (expand_asm_operands): Don't use TREE_STRING_LENGTH for
constraints.
(pushcase{,_range}): Convert to NOMINAL_TYPE after checking for
within INDEX_TYPE, instead of before.
(fixup_gotos): Use f->target_rtl, not the next insn,
since latter may be from a later fixup.
(expand_value_return): Correctly convert VAL when promoting function
return; support RETURN_REG being a PARALLEL.
(expand_return): When checking for result in regs and having
cleanup, consider PARALLEL in DECL_RTL as being in regs.
From-SVN: r30299
1999-11-01 02:11:22 +01:00
|
|
|
|
bb_file = fopen (bb_file_name, "rb");
|
1997-03-28 23:43:13 +01:00
|
|
|
|
if (bb_file == NULL)
|
|
|
|
|
{
|
1999-01-27 02:43:17 +01:00
|
|
|
|
fnotice (stderr, "Could not open basic block file %s.\n", bb_file_name);
|
1997-04-13 20:19:11 +02:00
|
|
|
|
exit (FATAL_EXIT_CODE);
|
1997-03-28 23:43:13 +01:00
|
|
|
|
}
|
|
|
|
|
|
2002-08-04 19:06:10 +02:00
|
|
|
|
bbg_file = fopen (bbg_file_name, "rb");
|
|
|
|
|
if (bbg_file == NULL)
|
|
|
|
|
{
|
|
|
|
|
fnotice (stderr, "Could not open program flow graph file %s.\n",
|
|
|
|
|
bbg_file_name);
|
|
|
|
|
exit (FATAL_EXIT_CODE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
struct stat status;
|
|
|
|
|
|
|
|
|
|
if (!fstat (fileno (bb_file), &status))
|
|
|
|
|
bb_file_time = status.st_mtime;
|
|
|
|
|
}
|
|
|
|
|
|
1997-03-28 23:43:13 +01:00
|
|
|
|
/* If none of the functions in the file were executed, then there won't
|
|
|
|
|
be a .da file. Just assume that all counts are zero in this case. */
|
[multiple changes]
Fri Oct 29 15:25:07 1999 Arnaud Charlet <charlet@ACT-Europe.FR>
* gcov.c (DIR_SEPARATOR): Provide default.
(output_data): Add test for MS-DOS format absolute filename.
(fancy_abort): Correct program name.
(open_files): Open all files in binary mode.
* libgcc2.c (__bb_exit_func): Likewise.
* profile.c (init_branch_prob): Specify binary when opening files.
* flags.h (flag_unwind_tables): New decl.
* toplev.c (flag_unwind_table): New definition.
(f_options): Add -funwind-tables.
(decode_g_option): Clarify warning when unknown -g option is given.
(rest_of_compilation): If inside an inlined external function,
pretend we are just being declared.
* dwarf2out.c (dwarf2out_do_frame): Check -funwind_tables.
(dwarf2out_frame_finish): Likewise.
Fri Oct 29 06:32:44 1999 Geoffrey Keating <geoffk@cygnus.com>
* flow.c (propagate_block): When the last reference to a label
before an ADDR_VEC is deleted because the reference is a dead
store, delete the ADDR_VEC.
Fri Oct 29 07:44:26 1999 Vasco Pedro <vp@di.fct.unl.pt>
* fold-const.c (merge_ranges): In not in0, but in1, handle
upper bounds equal like subset case.
Thu Oct 28 19:22:24 1999 Douglas Rupp <rupp@gnat.com>
* dbxout.c (dbxout_parms): Generate a second stabs line for parameters
passed in a register but moved to the stack.
Thu Oct 28 19:12:57 1999 Sam Tardieu <tardieu@act-europe.fr>
* gcc.c (pass_exit_codes, greatest_status): New variables.
(struct option_map): Add entry for "--pass-exit-codes".
(execute): Update greatest_status if error.
(display_help): Add documentation for -pass-exit-codes.
(process_command): Handle -pass-exit-codes.
(main): Look at pass_exit_codes and greatest_status on call to exit.
Thu Oct 28 18:06:50 1999 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
* reload.c (find_reloads): Refine test for no input reload
case to not includes reloads emitted after insn.
* function.c (find_temp_slots_from_address): Handle sum involving
a register that points to a temp slot.
(update_temp_slot_address): Make recursive call if both old and
new are PLUS with a common operand.
* calls.c (expand_call): Mark temp slot for result as having
address taken.
* rtlanal.c (reg_referenced_p, case IF_THEN_ELSE): New case.
* gcc.c (process_command): Add standard_exec_prefix with "GCC"
component as well as "BINUTILS".
* integrate.h (copy_rtx_and_substitute): New arg, FOR_LHS.
* integrate.c (copy_rtx_and_substitute): Likewise.
(expand_inline_function, integrate_parm_decls, integrate_decl_tree):
All callers changed.
* unroll.c (inital_reg_note_copy, copy_loop_body): Likewise.
* dbxout.c (dbxout_type, case INTEGER_TYPE_NODE): If can use
gdb extensions, write size of type; also be more consistent
in using references when this is a subtype.
* pa.md (extv, extzv, insv): Use define_expand to reject constant
that is out of range.
* loop.c (unknown_constant_address_altered): New variable.
(prescan_loop): Initialize it.
(note_addr_stored): Set it for RTX_UNCHANGING_P MEM.
(invariant_p, case MEM): Remove handling for volatile and readony;
check new variable if readonly.
(check_dbra_loop): Chdeck unknown_constant_address_altered.
* cse.c (canon_hash, case MEM): Do not record if BLKmode.
(addr_affects_sp_p): Removed from note_mem_written and only
define #ifdef AUTO_INC_DEC.
* alpha.c (input_operand, case ADDRESSOF): Treat as REG.
* regclass.c (record_reg_classes): Properly handle register move
directions.
* varasm.c (initializer_constant_valid_p, case MINUS_EXPR):
Don't think valid if both operands are invalid.
(struct constant_descriptor): New field RTL.
(mark_const_hash_entry): Mark it.
(record_constant{,_rtx}): Initialize it.
(output_constant_def): Allocate RTL in permanent obstack and
save in table.
({record,compare}_constant_1): Modes must match for
CONSTRUCTOR of ARRAY_TYPE.
* c-common.h (initializer_constant_valid_p): Delete decl from here.
* output.h (initializer_constant_valid_p): Move decl to here.
* c-common.c (initializer_constant_valid_p): Delete function from here.
* varasm.c (initializer_constant_valid_p): Move function to here.
* tree.h (STRIP_SIGN_NOPS): New macro.
* fold-const.c (optimize_minmax_comparison): New function.
(invert_truthvalue, case WITH_RECORD_EXPR): New case.
(fold): Use STRIP_SIGN_NOPS instead of STRIP_TYPE_NOPS.
(fold, case EQ_EXPR): Call optimize_minmax_comparison and add
cases with ABS_EXPR, NEGATE_EXPR, PLUS_EXPR, MINUS_EXPR, and
widening conversions.
(fold, case LE_EXPR): Rework changing unsigned to signed comparisons
to look at size of mode, not precision of type; also add missing cases.
(optimize_bit_field_compare, decode_field_reference): Don't try to
optimize COMPONENT_REF of a PLACEHOLDER_EXPR.
* dwarf2out.c (ctype.h): Include.
(dwarf2out_set_demangle_name_func): New function.
(size_of_line_info): Deleted.
(output_line_info): Compute size of line info table from difference
of labels.
(base_type_die, add_name_attribute): Call demangle function, if any.
(field_byte_offset): Use bits per word for variable length fields.
(gen_array_type_die): Add array name.
(gen_subprogram_die): Ignore DECL_INLINE if -fno-inline.
(dwarf2out_add_library_unit_info): New function.
* explow.c (set_stack_check_libfunc): New function.
(stack_check_libfunc): New static variable.
(probe_stack_range): Allow front-end to set up a libfunc to call.
* combine.c (simplify_comparison): When making comparison in wider
mode, check for having commuted an AND and a SUBREG.
(contains_muldiv): New function.
(try_combine): Call it when dividing a PARALLEL.
(simplify_rtx, case TRUNCATE): Don't remove for umulsi3_highpart.
(simplify_comparison, case ASHIFTRT): Recognize sign-extension of
a PLUS.
(record_value_for_reg): If TEM is a binary operation with two CLOBBERs,
use one of the CLOBBERs instead.
(if_then_else_cond): If comparing against zero, just return thing
being compared.
* optabs.c (expand_abs): If machine has MAX, ABS (x) is MAX (x, -x).
Don't generate shifts and subtract if have conditional arithmetic.
* rtl.h (delete_barrier): New declaration.
* jump.c (jump_optimize): Set up to handle conditional call.
In conditional arithmetic case, handle CALL_INSN followed by a BARRIER.
(delete_barrier): New function.
* rtl.c (read_rtx): Call fatal if bad RTL code; check for bad mode.
* recog.c (nonmemory_operand): Accept ADDRESSOF.
* tree.c (build_type_attribute_variant): Push to obstack of
ttype around type_hash_canon call.
* expr.c (placeholder_list): Move decl to file scope.
(expand_expr): Don't force access to volatile just because its
address is taken.
If ignoring reference operations, just expand the operands.
(expand_expr, case COMPONENT_REF): Propagate
EXPAND_CONST_ADDRESS to recursive call when expanding inner.
Refine test for using bitfield operations vs pointer punning.
(expand_expr, case CONVERT_EXPR): If converting to
BLKmode UNION_TYPE from BLKmode, just return inner object.
Use proper mode in store_field call.
Properly set sizes of object to store and total size in store_field
call for convert to union.
(expand_expr, case ARRAY_REF): If OP0 is in a register, put it in
memory (like for ADDR_EXPR). Also, don't put constant in register if
we'll want it in memory.
(readonly_fields_p): New function.
(expand_expr, case INDIRECT_REF): Call it if LHS.
(expand_assignment): Handle a RESULT_DECL where
DECL_RTL is a PARALLEL.
(do_jump, case WITH_RECORD_EXPR): New case.
(get_inner_reference): Always go inside a CONVERT_EXPR
and NOP_EXPR if both modes are the same.
(store_field): Use bitfield operations if size of bitsize is not same
as size of RHS's type.
Check for bitpos not a multiple of alignment in BLKmode case.
Do block move in largest possible alignment.
(store_constructor): Set BITSIZE to -1 for variable size and properly
in case of array of BLKmode.
(expand_expr_unaligned): New function.
(do_compare_and_jump): Call it.
* mips/iris5.h (SWITCHES_NEED_SPACES): New macro.
* collect2.c (main): Only allow -ofoo if SWITCHES_NEED_SPACES
does not include 'o'.
* function.c (instantiate_virtual_regs_1, case SET): Handle case where
both SET_DEST and SET_SRC reference a virtual register.
(gen_mem_addressof): Copy RTX_UNCHANGING_P from new REG to old REG.
* integrate.c (expand_inline_function): Handle case of setting
virtual stack vars register (from built in setjmp); when parameter
lives in memory, expand virtual_{stack_vars,incoming_args}_rtx early.
(subst_constant): Add new parm, MEMONLY.
(expand_inline_function, integrate_parm_decls): Pass new parm.
(integrate_decl_tree): Likewise.
(copy_rtx_and_substitute, case MEM): Do copy RTX_UNCHANGING_P.
(try_constants): Call subst_constants twice, with MEMONLY 0 and 1.
(copy_rtx_and_substitute, case SET): Add explicit calls to
copy_rtx_and_substitute for both sides.
* stmt.c (expand_asm_operands): Don't use TREE_STRING_LENGTH for
constraints.
(pushcase{,_range}): Convert to NOMINAL_TYPE after checking for
within INDEX_TYPE, instead of before.
(fixup_gotos): Use f->target_rtl, not the next insn,
since latter may be from a later fixup.
(expand_value_return): Correctly convert VAL when promoting function
return; support RETURN_REG being a PARALLEL.
(expand_return): When checking for result in regs and having
cleanup, consider PARALLEL in DECL_RTL as being in regs.
From-SVN: r30299
1999-11-01 02:11:22 +01:00
|
|
|
|
da_file = fopen (da_file_name, "rb");
|
1997-03-28 23:43:13 +01:00
|
|
|
|
if (da_file == NULL)
|
|
|
|
|
{
|
1999-01-27 02:43:17 +01:00
|
|
|
|
fnotice (stderr, "Could not open data file %s.\n", da_file_name);
|
|
|
|
|
fnotice (stderr, "Assuming that all execution counts are zero.\n");
|
1997-03-28 23:43:13 +01:00
|
|
|
|
}
|
2001-07-16 11:16:04 +02:00
|
|
|
|
|
1997-03-28 23:43:13 +01:00
|
|
|
|
/* Check for empty .bbg file. This indicates that there is no executable
|
|
|
|
|
code in this source file. */
|
|
|
|
|
/* Set the EOF condition if at the end of file. */
|
|
|
|
|
ungetc (getc (bbg_file), bbg_file);
|
|
|
|
|
if (feof (bbg_file))
|
|
|
|
|
{
|
1999-01-27 02:43:17 +01:00
|
|
|
|
fnotice (stderr, "No executable code associated with file %s.\n",
|
1997-03-28 23:43:13 +01:00
|
|
|
|
input_file_name);
|
1997-04-13 20:19:11 +02:00
|
|
|
|
exit (FATAL_EXIT_CODE);
|
1997-03-28 23:43:13 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Initialize a new arc. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
init_arc (arcptr, source, target, bb_graph)
|
|
|
|
|
struct adj_list *arcptr;
|
|
|
|
|
int source, target;
|
|
|
|
|
struct bb_info *bb_graph;
|
|
|
|
|
{
|
|
|
|
|
arcptr->target = target;
|
|
|
|
|
arcptr->source = source;
|
|
|
|
|
|
|
|
|
|
arcptr->arc_count = 0;
|
|
|
|
|
arcptr->count_valid = 0;
|
|
|
|
|
arcptr->on_tree = 0;
|
|
|
|
|
arcptr->fake = 0;
|
|
|
|
|
arcptr->fall_through = 0;
|
|
|
|
|
|
|
|
|
|
arcptr->succ_next = bb_graph[source].succ;
|
|
|
|
|
bb_graph[source].succ = arcptr;
|
|
|
|
|
bb_graph[source].succ_count++;
|
|
|
|
|
|
|
|
|
|
arcptr->pred_next = bb_graph[target].pred;
|
|
|
|
|
bb_graph[target].pred = arcptr;
|
|
|
|
|
bb_graph[target].pred_count++;
|
|
|
|
|
}
|
|
|
|
|
|
2001-10-09 08:03:16 +02:00
|
|
|
|
/* Reverse the arcs on an arc list. */
|
1997-03-28 23:43:13 +01:00
|
|
|
|
|
|
|
|
|
static struct adj_list *
|
|
|
|
|
reverse_arcs (arcptr)
|
|
|
|
|
struct adj_list *arcptr;
|
|
|
|
|
{
|
|
|
|
|
struct adj_list *prev = 0;
|
|
|
|
|
struct adj_list *next;
|
|
|
|
|
|
|
|
|
|
for ( ; arcptr; arcptr = next)
|
|
|
|
|
{
|
|
|
|
|
next = arcptr->succ_next;
|
|
|
|
|
arcptr->succ_next = prev;
|
|
|
|
|
prev = arcptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return prev;
|
|
|
|
|
}
|
|
|
|
|
|
2002-05-09 14:54:19 +02:00
|
|
|
|
/* Reads profiles from the .da file and compute a hybrid profile. */
|
|
|
|
|
|
|
|
|
|
static gcov_type *
|
|
|
|
|
read_profile (function_name, cfg_checksum, instr_arcs)
|
|
|
|
|
char *function_name;
|
|
|
|
|
long cfg_checksum;
|
|
|
|
|
int instr_arcs;
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
int okay = 1;
|
|
|
|
|
gcov_type *profile;
|
|
|
|
|
char *function_name_buffer;
|
|
|
|
|
int function_name_buffer_len;
|
|
|
|
|
|
|
|
|
|
profile = xmalloc (sizeof (gcov_type) * instr_arcs);
|
|
|
|
|
function_name_buffer_len = strlen (function_name) + 1;
|
|
|
|
|
function_name_buffer = xmalloc (function_name_buffer_len + 1);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < instr_arcs; i++)
|
|
|
|
|
profile[i] = 0;
|
|
|
|
|
|
|
|
|
|
if (!da_file)
|
|
|
|
|
return profile;
|
|
|
|
|
|
2002-08-04 19:06:10 +02:00
|
|
|
|
rewind (da_file);
|
2002-05-09 14:54:19 +02:00
|
|
|
|
while (1)
|
|
|
|
|
{
|
|
|
|
|
long magic, extra_bytes;
|
|
|
|
|
long func_count;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if (__read_long (&magic, da_file, 4) != 0)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (magic != -123)
|
|
|
|
|
{
|
|
|
|
|
okay = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (__read_long (&func_count, da_file, 4) != 0)
|
|
|
|
|
{
|
|
|
|
|
okay = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (__read_long (&extra_bytes, da_file, 4) != 0)
|
|
|
|
|
{
|
|
|
|
|
okay = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* skip extra data emited by __bb_exit_func. */
|
|
|
|
|
fseek (da_file, extra_bytes, SEEK_CUR);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < func_count; i++)
|
|
|
|
|
{
|
|
|
|
|
long arc_count;
|
|
|
|
|
long chksum;
|
|
|
|
|
int j;
|
|
|
|
|
|
|
|
|
|
if (__read_gcov_string
|
|
|
|
|
(function_name_buffer, function_name_buffer_len, da_file,
|
|
|
|
|
-1) != 0)
|
|
|
|
|
{
|
|
|
|
|
okay = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (__read_long (&chksum, da_file, 4) != 0)
|
|
|
|
|
{
|
|
|
|
|
okay = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (__read_long (&arc_count, da_file, 4) != 0)
|
|
|
|
|
{
|
|
|
|
|
okay = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (strcmp (function_name_buffer, function_name) != 0
|
|
|
|
|
|| arc_count != instr_arcs || chksum != cfg_checksum)
|
|
|
|
|
{
|
|
|
|
|
/* skip */
|
|
|
|
|
if (fseek (da_file, arc_count * 8, SEEK_CUR) < 0)
|
|
|
|
|
{
|
|
|
|
|
okay = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
gcov_type tmp;
|
|
|
|
|
|
|
|
|
|
for (j = 0; j < arc_count; j++)
|
|
|
|
|
if (__read_gcov_type (&tmp, da_file, 8) != 0)
|
|
|
|
|
{
|
|
|
|
|
okay = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
profile[j] += tmp;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!okay)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free (function_name_buffer);
|
|
|
|
|
|
|
|
|
|
if (!okay)
|
|
|
|
|
{
|
|
|
|
|
fprintf (stderr, ".da file corrupted!\n");
|
|
|
|
|
free (profile);
|
|
|
|
|
abort ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return profile;
|
|
|
|
|
}
|
1997-03-28 23:43:13 +01:00
|
|
|
|
|
|
|
|
|
/* Construct the program flow graph from the .bbg file, and read in the data
|
|
|
|
|
in the .da file. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
create_program_flow_graph (bptr)
|
|
|
|
|
struct bb_info_list *bptr;
|
|
|
|
|
{
|
|
|
|
|
long num_blocks, number_arcs, src, dest, flag_bits, num_arcs_per_block;
|
|
|
|
|
int i;
|
|
|
|
|
struct adj_list *arcptr;
|
|
|
|
|
struct bb_info *bb_graph;
|
2002-05-09 14:54:19 +02:00
|
|
|
|
long cfg_checksum;
|
|
|
|
|
long instr_arcs = 0;
|
|
|
|
|
gcov_type *profile;
|
|
|
|
|
int profile_pos = 0;
|
|
|
|
|
char *function_name;
|
|
|
|
|
long function_name_len, tmp;
|
|
|
|
|
|
|
|
|
|
/* Read function name. */
|
|
|
|
|
__read_long (&tmp, bbg_file, 4); /* ignore -1. */
|
|
|
|
|
__read_long (&function_name_len, bbg_file, 4);
|
|
|
|
|
function_name = xmalloc (function_name_len + 1);
|
|
|
|
|
fread (function_name, 1, function_name_len + 1, bbg_file);
|
2002-06-04 13:30:46 +02:00
|
|
|
|
|
2002-05-09 14:54:19 +02:00
|
|
|
|
/* Skip padding. */
|
|
|
|
|
tmp = (function_name_len + 1) % 4;
|
|
|
|
|
|
|
|
|
|
if (tmp)
|
|
|
|
|
fseek (bbg_file, 4 - tmp, SEEK_CUR);
|
|
|
|
|
|
|
|
|
|
__read_long (&tmp, bbg_file, 4); /* ignore -1. */
|
2002-06-04 13:30:46 +02:00
|
|
|
|
|
2002-05-09 14:54:19 +02:00
|
|
|
|
/* Read the cfg checksum. */
|
|
|
|
|
__read_long (&cfg_checksum, bbg_file, 4);
|
1997-03-28 23:43:13 +01:00
|
|
|
|
|
|
|
|
|
/* Read the number of blocks. */
|
|
|
|
|
__read_long (&num_blocks, bbg_file, 4);
|
|
|
|
|
|
c-aux-info.c (concat): Don't define.
* c-aux-info.c (concat): Don't define.
* cccp.c (my_strerror): Likewise. All callers changed to use
xstrerror instead.
(do_include): Call xstrdup, not xmalloc/strcpy.
(grow_outbuf): Don't check if xrealloc returns NULL, it can't.
(xmalloc, xrealloc, xcalloc, xstrdup): Don't define.
* collect2.c (my_strsignal): Likewise. All callers changed to use
strsignal instead.
(locatelib): Call xstrdup, not xmalloc/strcpy.
* 1750a.h (ASM_OUTPUT_INTERNAL_LABEL): Call xmalloc, not malloc.
* dsp16xx.c (override_options): Call xstrdup, not xmalloc/strcpy.
* i370.h (ASM_DECLARE_FUNCTION_NAME): Call xmalloc, not malloc.
* mips.c (build_mips16_call_stub): Call xstrdup, not xmalloc/strcpy.
* cppinit.c (cpp_options_init): Call xcalloc, not xmalloc/bzero.
* dwarfout.c (dwarfout_init): Call concat, not xmalloc/strcpy/...
* except.c (new_eh_region_entry): Call xmalloc/xrealloc, not
malloc/realloc.
(find_all_handler_type_matches): Likewise. Don't check return
value.
(get_new_handler, init_insn_eh_region, process_nestinfo): Call
xmalloc, not malloc.
(init_eh_nesting_info): Likewise. Call xcalloc, not xmalloc/bzero.
* gcc.c (xstrerror, xmalloc, xrealloc): Don't define.
(init_spec): Call xcalloc, not xmalloc/bzero.
(set_spec): Call xstrdup, not save_string.
(record_temp_file): Call xstrdup, not xmalloc/strcpy.
(find_a_file): Call xstrdup, not xmalloc/strcpy.
(process_command): Call xstrdup, not save_string.
(main): Call xcalloc, not xmalloc/bzero.
* gcov.c (xmalloc): Don't define.
(create_program_flow_graph): Call xcalloc, not xmalloc/bzero.
(scan_for_source_files): Call xstrdup, not xmalloc/strcpy.
(output_data): Call xcalloc, not xmalloc/bzero.
* haifa-sched.c (schedule_insns): Call xcalloc, not xmalloc/bzero.
* mips-tdump.c (xmalloc): Don't define.
(print_symbol): Call xmalloc, not malloc.
(read_tfile): Call xcalloc, not calloc.
* mips-tfile.c (xfree, my_strsignal, xmalloc, xcalloc, xrealloc):
Don't define. All callers of xfree/my_strsignal changed to use
free/strsignal instead.
(allocate_cluster): Call xcalloc, not calloc.
* objc/objc-act.c (lang_init): Call concat, not xmalloc/strcpy/...
Fix memory leak, free allocated memory.
* prefix.c (translate_name): Call xstrdup, not save_string.
(update_path): Likewise.
* profile.c (branch_prob): Call xstrdup, not xmalloc/strcpy.
* protoize.c (xstrerror, xmalloc, xrealloc, xfree, savestring2):
Don't define. Callers of xfree/savestring2 changed to use
free/concat instead.
* reload1.c (reload): Call xcalloc, not xmalloc/bzero.
(init_elim_table): Likewise.
* resource.c (init_resource_info): Likewise.
* stupid.c (stupid_life_analysis): Likewise.
* toplev.c (xmalloc, xcalloc, xrealloc, xstrdup): Don't define.
(open_dump_file): Call concat, not xmalloc/strcpy/...
(clean_dump_file): Likewise.
(compile_file): Call xstrdup, not xmalloc/strcpy.
From-SVN: r29148
1999-09-07 04:36:41 +02:00
|
|
|
|
/* Create an array of size bb number of bb_info structs. */
|
|
|
|
|
bb_graph = (struct bb_info *) xcalloc (num_blocks, sizeof (struct bb_info));
|
1997-03-28 23:43:13 +01:00
|
|
|
|
|
|
|
|
|
bptr->bb_graph = bb_graph;
|
|
|
|
|
bptr->num_blocks = num_blocks;
|
|
|
|
|
|
|
|
|
|
/* Read and create each arc from the .bbg file. */
|
|
|
|
|
__read_long (&number_arcs, bbg_file, 4);
|
|
|
|
|
for (i = 0; i < num_blocks; i++)
|
|
|
|
|
{
|
|
|
|
|
int j;
|
|
|
|
|
|
|
|
|
|
__read_long (&num_arcs_per_block, bbg_file, 4);
|
|
|
|
|
for (j = 0; j < num_arcs_per_block; j++)
|
|
|
|
|
{
|
|
|
|
|
if (number_arcs-- < 0)
|
|
|
|
|
abort ();
|
|
|
|
|
|
|
|
|
|
src = i;
|
|
|
|
|
__read_long (&dest, bbg_file, 4);
|
|
|
|
|
|
|
|
|
|
arcptr = (struct adj_list *) xmalloc (sizeof (struct adj_list));
|
|
|
|
|
init_arc (arcptr, src, dest, bb_graph);
|
|
|
|
|
|
|
|
|
|
__read_long (&flag_bits, bbg_file, 4);
|
2002-05-09 14:54:19 +02:00
|
|
|
|
if (flag_bits & 0x1)
|
|
|
|
|
arcptr->on_tree++;
|
2002-06-04 13:30:46 +02:00
|
|
|
|
else
|
2002-05-09 14:54:19 +02:00
|
|
|
|
instr_arcs++;
|
1997-03-28 23:43:13 +01:00
|
|
|
|
arcptr->fake = !! (flag_bits & 0x2);
|
|
|
|
|
arcptr->fall_through = !! (flag_bits & 0x4);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (number_arcs)
|
|
|
|
|
abort ();
|
|
|
|
|
|
|
|
|
|
/* Read and ignore the -1 separating the arc list from the arc list of the
|
|
|
|
|
next function. */
|
|
|
|
|
__read_long (&src, bbg_file, 4);
|
|
|
|
|
if (src != -1)
|
|
|
|
|
abort ();
|
|
|
|
|
|
|
|
|
|
/* Must reverse the order of all succ arcs, to ensure that they match
|
|
|
|
|
the order of the data in the .da file. */
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < num_blocks; i++)
|
|
|
|
|
if (bb_graph[i].succ)
|
|
|
|
|
bb_graph[i].succ = reverse_arcs (bb_graph[i].succ);
|
|
|
|
|
|
2002-05-09 14:54:19 +02:00
|
|
|
|
/* Read profile from the .da file. */
|
|
|
|
|
|
|
|
|
|
profile = read_profile (function_name, cfg_checksum, instr_arcs);
|
|
|
|
|
|
1997-03-28 23:43:13 +01:00
|
|
|
|
/* For each arc not on the spanning tree, set its execution count from
|
|
|
|
|
the .da file. */
|
|
|
|
|
|
|
|
|
|
/* The first count in the .da file is the number of times that the function
|
|
|
|
|
was entered. This is the exec_count for block zero. */
|
|
|
|
|
|
|
|
|
|
/* This duplicates code in branch_prob in profile.c. */
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < num_blocks; i++)
|
|
|
|
|
for (arcptr = bb_graph[i].succ; arcptr; arcptr = arcptr->succ_next)
|
|
|
|
|
if (! arcptr->on_tree)
|
|
|
|
|
{
|
2002-05-09 14:54:19 +02:00
|
|
|
|
arcptr->arc_count = profile[profile_pos++];
|
1997-03-28 23:43:13 +01:00
|
|
|
|
arcptr->count_valid = 1;
|
|
|
|
|
bb_graph[i].succ_count--;
|
|
|
|
|
bb_graph[arcptr->target].pred_count--;
|
|
|
|
|
}
|
2002-05-09 14:54:19 +02:00
|
|
|
|
free (profile);
|
|
|
|
|
free (function_name);
|
1997-03-28 23:43:13 +01:00
|
|
|
|
}
|
2001-07-16 11:16:04 +02:00
|
|
|
|
|
1997-03-28 23:43:13 +01:00
|
|
|
|
static void
|
|
|
|
|
solve_program_flow_graph (bptr)
|
|
|
|
|
struct bb_info_list *bptr;
|
|
|
|
|
{
|
regs.h (struct reg_info_def): Add freq field.
* regs.h (struct reg_info_def): Add freq field.
(REG_N_REFS): Update comment.
(REG_FREQ): New.
* regclass.c (scan_one_insn): Update REG_FREQ.
* flow.c (mark_set_1): Update REG_FREQ, make REG_N_SETS unweighted.
(attempt_auto_inc): Likewise.
(mark_used_reg): Likewise.
(try_pre_increment_1): Likewise.
* local-alloc.c (struct qty): Add freq field.
(alloc_qty): Set freq.
(update_equiv_regs): Set REG_FREQ.
(QTY_CMP_PRI): Use freq.
(combine_regs): Update qty->freq.
* global.c (struct allocno): Update comment for n_refs;
add freq field.
(local_reg_freq): New array.
(global_alloc): Update freq field;
allocate and initialize local_reg_freq.
(allocno_compare): Use freq field.
(find_reg): Likewise.
* reload1.c (count_pseudo): Use freq isntead of n_refs.
(count_spilled_pseudo): Likewise.
* tm.texi (GCOV_TYPE_SIZE): Document.
* basic-block.h (gcov_type): Define.
(struct edge_def): Use gcov_type for count field.
(struct basic_block_def): Likewise.
* defaults.h (GCOV_TYPE_SIZE): Define.
* final.c (end_final): Use GCOV_TYPE_SIZE.
* flow.c (dump_edge_info, dump_flow_info, dump_bb): Print count fields
using HOST_WIDEST_INT_PRINT_DEC.
* gcov-io.h (__fetch_gcov_type, __store_gcov_type, __read_gcov_type,
__write_gcov_type): New.
(store_long): Remove.
* gcov.c (gcov_type): Set default.
(struct adj_list): Use gcov_type for arc_count.
(bb_info): Use gcov_type for succ_count, pred_count and exec_count.
(create_program_flow_graph): Read arc_count properly.
(solve_program_flow_graph): 'total' is gcov_type.
(output_data): Line_counts is gcov_type, print it properly.
* libgcc2.c (struct bb): Counts is gcov_type.
(__bb_exit_func): Use __read_gcov_type and __write_gcov_type.
* profile.c (LONG_TYPE_SIZE, LONG_LONG_TYPE_SIZE): Set default.
(GCOV_TYPE_SIZE): Define.
(struct bb_info): succ_count and pred_count is gcov_type.
(compute_branch_probabilities): Use __read_gcov_type,
print read edges to the dump file.
(total): Is gcov_type.
(gen_edge_profiler): Use GCOV_TYPE_SIZE.
From-SVN: r43505
2001-06-22 19:18:23 +02:00
|
|
|
|
int passes, changes;
|
|
|
|
|
gcov_type total;
|
1997-03-28 23:43:13 +01:00
|
|
|
|
int i;
|
|
|
|
|
struct adj_list *arcptr;
|
|
|
|
|
struct bb_info *bb_graph;
|
|
|
|
|
int num_blocks;
|
|
|
|
|
|
|
|
|
|
num_blocks = bptr->num_blocks;
|
|
|
|
|
bb_graph = bptr->bb_graph;
|
|
|
|
|
|
|
|
|
|
/* For every block in the file,
|
|
|
|
|
- if every exit/entrance arc has a known count, then set the block count
|
|
|
|
|
- if the block count is known, and every exit/entrance arc but one has
|
|
|
|
|
a known execution count, then set the count of the remaining arc
|
|
|
|
|
|
|
|
|
|
As arc counts are set, decrement the succ/pred count, but don't delete
|
|
|
|
|
the arc, that way we can easily tell when all arcs are known, or only
|
|
|
|
|
one arc is unknown. */
|
|
|
|
|
|
|
|
|
|
/* The order that the basic blocks are iterated through is important.
|
|
|
|
|
Since the code that finds spanning trees starts with block 0, low numbered
|
|
|
|
|
arcs are put on the spanning tree in preference to high numbered arcs.
|
|
|
|
|
Hence, most instrumented arcs are at the end. Graph solving works much
|
|
|
|
|
faster if we propagate numbers from the end to the start.
|
|
|
|
|
|
|
|
|
|
This takes an average of slightly more than 3 passes. */
|
|
|
|
|
|
|
|
|
|
changes = 1;
|
|
|
|
|
passes = 0;
|
|
|
|
|
while (changes)
|
|
|
|
|
{
|
|
|
|
|
passes++;
|
|
|
|
|
changes = 0;
|
|
|
|
|
|
|
|
|
|
for (i = num_blocks - 1; i >= 0; i--)
|
|
|
|
|
{
|
|
|
|
|
if (! bb_graph[i].count_valid)
|
|
|
|
|
{
|
|
|
|
|
if (bb_graph[i].succ_count == 0)
|
|
|
|
|
{
|
|
|
|
|
total = 0;
|
|
|
|
|
for (arcptr = bb_graph[i].succ; arcptr;
|
|
|
|
|
arcptr = arcptr->succ_next)
|
|
|
|
|
total += arcptr->arc_count;
|
|
|
|
|
bb_graph[i].exec_count = total;
|
|
|
|
|
bb_graph[i].count_valid = 1;
|
|
|
|
|
changes = 1;
|
|
|
|
|
}
|
|
|
|
|
else if (bb_graph[i].pred_count == 0)
|
|
|
|
|
{
|
|
|
|
|
total = 0;
|
|
|
|
|
for (arcptr = bb_graph[i].pred; arcptr;
|
|
|
|
|
arcptr = arcptr->pred_next)
|
|
|
|
|
total += arcptr->arc_count;
|
|
|
|
|
bb_graph[i].exec_count = total;
|
|
|
|
|
bb_graph[i].count_valid = 1;
|
|
|
|
|
changes = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (bb_graph[i].count_valid)
|
|
|
|
|
{
|
|
|
|
|
if (bb_graph[i].succ_count == 1)
|
|
|
|
|
{
|
|
|
|
|
total = 0;
|
|
|
|
|
/* One of the counts will be invalid, but it is zero,
|
|
|
|
|
so adding it in also doesn't hurt. */
|
|
|
|
|
for (arcptr = bb_graph[i].succ; arcptr;
|
|
|
|
|
arcptr = arcptr->succ_next)
|
|
|
|
|
total += arcptr->arc_count;
|
|
|
|
|
/* Calculate count for remaining arc by conservation. */
|
|
|
|
|
total = bb_graph[i].exec_count - total;
|
|
|
|
|
/* Search for the invalid arc, and set its count. */
|
|
|
|
|
for (arcptr = bb_graph[i].succ; arcptr;
|
|
|
|
|
arcptr = arcptr->succ_next)
|
|
|
|
|
if (! arcptr->count_valid)
|
|
|
|
|
break;
|
|
|
|
|
if (! arcptr)
|
|
|
|
|
abort ();
|
|
|
|
|
arcptr->count_valid = 1;
|
|
|
|
|
arcptr->arc_count = total;
|
|
|
|
|
bb_graph[i].succ_count--;
|
|
|
|
|
|
|
|
|
|
bb_graph[arcptr->target].pred_count--;
|
|
|
|
|
changes = 1;
|
|
|
|
|
}
|
|
|
|
|
if (bb_graph[i].pred_count == 1)
|
|
|
|
|
{
|
|
|
|
|
total = 0;
|
|
|
|
|
/* One of the counts will be invalid, but it is zero,
|
|
|
|
|
so adding it in also doesn't hurt. */
|
|
|
|
|
for (arcptr = bb_graph[i].pred; arcptr;
|
|
|
|
|
arcptr = arcptr->pred_next)
|
|
|
|
|
total += arcptr->arc_count;
|
|
|
|
|
/* Calculate count for remaining arc by conservation. */
|
|
|
|
|
total = bb_graph[i].exec_count - total;
|
|
|
|
|
/* Search for the invalid arc, and set its count. */
|
|
|
|
|
for (arcptr = bb_graph[i].pred; arcptr;
|
|
|
|
|
arcptr = arcptr->pred_next)
|
|
|
|
|
if (! arcptr->count_valid)
|
|
|
|
|
break;
|
|
|
|
|
if (! arcptr)
|
|
|
|
|
abort ();
|
|
|
|
|
arcptr->count_valid = 1;
|
|
|
|
|
arcptr->arc_count = total;
|
|
|
|
|
bb_graph[i].pred_count--;
|
|
|
|
|
|
|
|
|
|
bb_graph[arcptr->source].succ_count--;
|
|
|
|
|
changes = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-07-16 11:16:04 +02:00
|
|
|
|
|
1997-03-28 23:43:13 +01:00
|
|
|
|
/* If the graph has been correctly solved, every block will have a
|
|
|
|
|
succ and pred count of zero. */
|
|
|
|
|
for (i = 0; i < num_blocks; i++)
|
|
|
|
|
if (bb_graph[i].succ_count || bb_graph[i].pred_count)
|
|
|
|
|
abort ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
read_files ()
|
|
|
|
|
{
|
|
|
|
|
struct stat buf;
|
|
|
|
|
struct bb_info_list *list_end = 0;
|
|
|
|
|
struct bb_info_list *b_ptr;
|
|
|
|
|
|
|
|
|
|
while (! feof (bbg_file))
|
|
|
|
|
{
|
|
|
|
|
b_ptr = (struct bb_info_list *) xmalloc (sizeof (struct bb_info_list));
|
|
|
|
|
|
|
|
|
|
b_ptr->next = 0;
|
|
|
|
|
if (list_end)
|
|
|
|
|
list_end->next = b_ptr;
|
|
|
|
|
else
|
|
|
|
|
bb_graph_list = b_ptr;
|
|
|
|
|
list_end = b_ptr;
|
|
|
|
|
|
|
|
|
|
/* Read in the data in the .bbg file and reconstruct the program flow
|
|
|
|
|
graph for one function. */
|
1997-12-20 12:31:54 +01:00
|
|
|
|
create_program_flow_graph (b_ptr);
|
1997-03-28 23:43:13 +01:00
|
|
|
|
|
|
|
|
|
/* Set the EOF condition if at the end of file. */
|
|
|
|
|
ungetc (getc (bbg_file), bbg_file);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Calculate all of the basic block execution counts and branch
|
|
|
|
|
taken probabilities. */
|
|
|
|
|
|
|
|
|
|
for (b_ptr = bb_graph_list; b_ptr; b_ptr = b_ptr->next)
|
|
|
|
|
solve_program_flow_graph (b_ptr);
|
|
|
|
|
|
|
|
|
|
/* Read in all of the data from the .bb file. This info will be accessed
|
|
|
|
|
sequentially twice. */
|
|
|
|
|
stat (bb_file_name, &buf);
|
|
|
|
|
bb_data_size = buf.st_size / 4;
|
|
|
|
|
|
1997-12-20 12:31:54 +01:00
|
|
|
|
bb_data = (char *) xmalloc ((unsigned) buf.st_size);
|
1997-03-28 23:43:13 +01:00
|
|
|
|
fread (bb_data, sizeof (char), buf.st_size, bb_file);
|
2001-07-16 11:16:04 +02:00
|
|
|
|
|
1997-03-28 23:43:13 +01:00
|
|
|
|
fclose (bb_file);
|
|
|
|
|
if (da_file)
|
|
|
|
|
fclose (da_file);
|
|
|
|
|
fclose (bbg_file);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Scan the data in the .bb file to find all source files referenced,
|
|
|
|
|
and the largest line number mentioned in each one. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
scan_for_source_files ()
|
|
|
|
|
{
|
1997-12-20 12:31:54 +01:00
|
|
|
|
struct sourcefile *s_ptr = NULL;
|
1997-03-28 23:43:13 +01:00
|
|
|
|
char *ptr;
|
2001-07-30 20:04:33 +02:00
|
|
|
|
long count;
|
1997-03-28 23:43:13 +01:00
|
|
|
|
long line_num;
|
|
|
|
|
|
|
|
|
|
/* Search the bb_data to find:
|
|
|
|
|
1) The number of sources files contained herein, and
|
|
|
|
|
2) The largest line number for each source file. */
|
|
|
|
|
|
|
|
|
|
ptr = bb_data;
|
|
|
|
|
sources = 0;
|
|
|
|
|
for (count = 0; count < bb_data_size; count++)
|
|
|
|
|
{
|
|
|
|
|
__fetch_long (&line_num, ptr, 4);
|
|
|
|
|
ptr += 4;
|
|
|
|
|
if (line_num == -1)
|
|
|
|
|
{
|
|
|
|
|
/* A source file name follows. Check to see if we already have
|
|
|
|
|
a sourcefile structure for this file. */
|
|
|
|
|
s_ptr = sources;
|
|
|
|
|
while (s_ptr && strcmp (s_ptr->name, ptr))
|
|
|
|
|
s_ptr = s_ptr->next;
|
|
|
|
|
|
|
|
|
|
if (s_ptr == 0)
|
|
|
|
|
{
|
|
|
|
|
/* No sourcefile structure for this file name exists, create
|
|
|
|
|
a new one, and append it to the front of the sources list. */
|
|
|
|
|
s_ptr = (struct sourcefile *) xmalloc (sizeof(struct sourcefile));
|
c-aux-info.c (concat): Don't define.
* c-aux-info.c (concat): Don't define.
* cccp.c (my_strerror): Likewise. All callers changed to use
xstrerror instead.
(do_include): Call xstrdup, not xmalloc/strcpy.
(grow_outbuf): Don't check if xrealloc returns NULL, it can't.
(xmalloc, xrealloc, xcalloc, xstrdup): Don't define.
* collect2.c (my_strsignal): Likewise. All callers changed to use
strsignal instead.
(locatelib): Call xstrdup, not xmalloc/strcpy.
* 1750a.h (ASM_OUTPUT_INTERNAL_LABEL): Call xmalloc, not malloc.
* dsp16xx.c (override_options): Call xstrdup, not xmalloc/strcpy.
* i370.h (ASM_DECLARE_FUNCTION_NAME): Call xmalloc, not malloc.
* mips.c (build_mips16_call_stub): Call xstrdup, not xmalloc/strcpy.
* cppinit.c (cpp_options_init): Call xcalloc, not xmalloc/bzero.
* dwarfout.c (dwarfout_init): Call concat, not xmalloc/strcpy/...
* except.c (new_eh_region_entry): Call xmalloc/xrealloc, not
malloc/realloc.
(find_all_handler_type_matches): Likewise. Don't check return
value.
(get_new_handler, init_insn_eh_region, process_nestinfo): Call
xmalloc, not malloc.
(init_eh_nesting_info): Likewise. Call xcalloc, not xmalloc/bzero.
* gcc.c (xstrerror, xmalloc, xrealloc): Don't define.
(init_spec): Call xcalloc, not xmalloc/bzero.
(set_spec): Call xstrdup, not save_string.
(record_temp_file): Call xstrdup, not xmalloc/strcpy.
(find_a_file): Call xstrdup, not xmalloc/strcpy.
(process_command): Call xstrdup, not save_string.
(main): Call xcalloc, not xmalloc/bzero.
* gcov.c (xmalloc): Don't define.
(create_program_flow_graph): Call xcalloc, not xmalloc/bzero.
(scan_for_source_files): Call xstrdup, not xmalloc/strcpy.
(output_data): Call xcalloc, not xmalloc/bzero.
* haifa-sched.c (schedule_insns): Call xcalloc, not xmalloc/bzero.
* mips-tdump.c (xmalloc): Don't define.
(print_symbol): Call xmalloc, not malloc.
(read_tfile): Call xcalloc, not calloc.
* mips-tfile.c (xfree, my_strsignal, xmalloc, xcalloc, xrealloc):
Don't define. All callers of xfree/my_strsignal changed to use
free/strsignal instead.
(allocate_cluster): Call xcalloc, not calloc.
* objc/objc-act.c (lang_init): Call concat, not xmalloc/strcpy/...
Fix memory leak, free allocated memory.
* prefix.c (translate_name): Call xstrdup, not save_string.
(update_path): Likewise.
* profile.c (branch_prob): Call xstrdup, not xmalloc/strcpy.
* protoize.c (xstrerror, xmalloc, xrealloc, xfree, savestring2):
Don't define. Callers of xfree/savestring2 changed to use
free/concat instead.
* reload1.c (reload): Call xcalloc, not xmalloc/bzero.
(init_elim_table): Likewise.
* resource.c (init_resource_info): Likewise.
* stupid.c (stupid_life_analysis): Likewise.
* toplev.c (xmalloc, xcalloc, xrealloc, xstrdup): Don't define.
(open_dump_file): Call concat, not xmalloc/strcpy/...
(clean_dump_file): Likewise.
(compile_file): Call xstrdup, not xmalloc/strcpy.
From-SVN: r29148
1999-09-07 04:36:41 +02:00
|
|
|
|
s_ptr->name = xstrdup (ptr);
|
1997-03-28 23:43:13 +01:00
|
|
|
|
s_ptr->maxlineno = 0;
|
|
|
|
|
s_ptr->next = sources;
|
|
|
|
|
sources = s_ptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Scan past the file name. */
|
|
|
|
|
{
|
|
|
|
|
long delim;
|
|
|
|
|
do {
|
|
|
|
|
count++;
|
|
|
|
|
__fetch_long (&delim, ptr, 4);
|
|
|
|
|
ptr += 4;
|
|
|
|
|
} while (delim != line_num);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (line_num == -2)
|
|
|
|
|
{
|
|
|
|
|
long delim;
|
|
|
|
|
|
|
|
|
|
/* A function name follows. Ignore it. */
|
|
|
|
|
do {
|
|
|
|
|
count++;
|
|
|
|
|
__fetch_long (&delim, ptr, 4);
|
|
|
|
|
ptr += 4;
|
|
|
|
|
} while (delim != line_num);
|
|
|
|
|
}
|
|
|
|
|
/* There will be a zero before the first file name, in which case s_ptr
|
|
|
|
|
will still be uninitialized. So, only try to set the maxlineno
|
2002-09-22 16:09:34 +02:00
|
|
|
|
field if line_num is nonzero. */
|
1997-03-28 23:43:13 +01:00
|
|
|
|
else if (line_num > 0)
|
|
|
|
|
{
|
|
|
|
|
if (s_ptr->maxlineno <= line_num)
|
|
|
|
|
s_ptr->maxlineno = line_num + 1;
|
|
|
|
|
}
|
|
|
|
|
else if (line_num < 0)
|
|
|
|
|
{
|
2001-08-13 01:40:53 +02:00
|
|
|
|
/* Don't know what this is, but it's garbage. */
|
2002-01-05 23:11:21 +01:00
|
|
|
|
abort ();
|
1997-03-28 23:43:13 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2002-08-07 01:18:01 +02:00
|
|
|
|
/* Increment totals in FUNCTION according to arc A_PTR. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
accumulate_branch_counts (function, a_ptr)
|
|
|
|
|
struct coverage *function;
|
|
|
|
|
struct arcdata *a_ptr;
|
|
|
|
|
{
|
|
|
|
|
if (a_ptr->call_insn)
|
|
|
|
|
{
|
|
|
|
|
function->calls++;
|
|
|
|
|
if (a_ptr->total)
|
|
|
|
|
function->calls_executed++;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
function->branches++;
|
|
|
|
|
if (a_ptr->total)
|
|
|
|
|
function->branches_executed++;
|
|
|
|
|
if (a_ptr->hits)
|
|
|
|
|
function->branches_taken++;
|
|
|
|
|
}
|
|
|
|
|
}
|
1997-03-28 23:43:13 +01:00
|
|
|
|
|
|
|
|
|
/* Calculate the branch taken probabilities for all arcs branches at the
|
|
|
|
|
end of this block. */
|
|
|
|
|
|
|
|
|
|
static void
|
2002-08-07 01:18:01 +02:00
|
|
|
|
calculate_branch_probs (block_ptr, line_info, function)
|
|
|
|
|
struct bb_info *block_ptr;
|
|
|
|
|
struct line_info *line_info;
|
|
|
|
|
struct coverage *function;
|
1997-03-28 23:43:13 +01:00
|
|
|
|
{
|
2001-07-30 20:04:33 +02:00
|
|
|
|
gcov_type total;
|
1997-03-28 23:43:13 +01:00
|
|
|
|
struct adj_list *arcptr;
|
|
|
|
|
|
2002-08-07 01:18:01 +02:00
|
|
|
|
total = block_ptr->exec_count;
|
|
|
|
|
for (arcptr = block_ptr->succ; arcptr; arcptr = arcptr->succ_next)
|
1997-03-28 23:43:13 +01:00
|
|
|
|
{
|
2002-08-07 01:18:01 +02:00
|
|
|
|
struct arcdata *a_ptr;
|
|
|
|
|
|
1997-03-28 23:43:13 +01:00
|
|
|
|
/* Ignore fall through arcs as they aren't really branches. */
|
|
|
|
|
if (arcptr->fall_through)
|
|
|
|
|
continue;
|
2001-07-16 11:16:04 +02:00
|
|
|
|
|
1997-03-28 23:43:13 +01:00
|
|
|
|
a_ptr = (struct arcdata *) xmalloc (sizeof (struct arcdata));
|
1999-11-10 18:17:15 +01:00
|
|
|
|
a_ptr->total = total;
|
2002-08-07 01:18:01 +02:00
|
|
|
|
a_ptr->hits = total ? arcptr->arc_count : 0;
|
1997-03-28 23:43:13 +01:00
|
|
|
|
a_ptr->call_insn = arcptr->fake;
|
|
|
|
|
|
2002-08-07 01:18:01 +02:00
|
|
|
|
if (function)
|
|
|
|
|
accumulate_branch_counts (function, a_ptr);
|
|
|
|
|
/* Prepend the new branch to the list. */
|
|
|
|
|
a_ptr->next = line_info->branches;
|
|
|
|
|
line_info->branches = a_ptr;
|
1997-03-28 23:43:13 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2002-08-04 19:06:10 +02:00
|
|
|
|
/* Format a HOST_WIDE_INT as either a percent ratio, or absolute
|
|
|
|
|
count. If dp >= 0, format TOP/BOTTOM * 100 to DP decimal places.
|
|
|
|
|
If DP is zero, no decimal point is printed. Only print 100% when
|
|
|
|
|
TOP==BOTTOM and only print 0% when TOP=0. If dp < 0, then simply
|
|
|
|
|
format TOP. Return pointer to a static string. */
|
|
|
|
|
|
|
|
|
|
static char const *
|
|
|
|
|
format_hwint (top, bottom, dp)
|
|
|
|
|
HOST_WIDEST_INT top, bottom;
|
|
|
|
|
int dp;
|
|
|
|
|
{
|
|
|
|
|
static char buffer[20];
|
|
|
|
|
|
|
|
|
|
if (dp >= 0)
|
|
|
|
|
{
|
|
|
|
|
float ratio = bottom ? (float)top / bottom : 0;
|
|
|
|
|
int ix;
|
|
|
|
|
unsigned limit = 100;
|
|
|
|
|
unsigned percent;
|
|
|
|
|
|
|
|
|
|
for (ix = dp; ix--; )
|
|
|
|
|
limit *= 10;
|
|
|
|
|
|
2002-08-06 00:16:51 +02:00
|
|
|
|
percent = (unsigned) (ratio * limit + (float)0.5);
|
|
|
|
|
if (percent <= 0 && top)
|
2002-08-04 19:06:10 +02:00
|
|
|
|
percent = 1;
|
2002-08-06 00:16:51 +02:00
|
|
|
|
else if (percent >= limit && top != bottom)
|
2002-08-04 19:06:10 +02:00
|
|
|
|
percent = limit - 1;
|
|
|
|
|
ix = sprintf (buffer, "%.*u%%", dp + 1, percent);
|
|
|
|
|
if (dp)
|
|
|
|
|
{
|
|
|
|
|
dp++;
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
buffer[ix+1] = buffer[ix];
|
|
|
|
|
ix--;
|
|
|
|
|
}
|
|
|
|
|
while (dp--);
|
|
|
|
|
buffer[ix + 1] = '.';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
sprintf (buffer, HOST_WIDEST_INT_PRINT_DEC, top);
|
|
|
|
|
|
|
|
|
|
return buffer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1997-03-28 23:43:13 +01:00
|
|
|
|
/* Output summary info for a function. */
|
|
|
|
|
|
|
|
|
|
static void
|
2002-08-07 01:18:01 +02:00
|
|
|
|
function_summary (function, title)
|
|
|
|
|
struct coverage *function;
|
|
|
|
|
const char *title;
|
1997-03-28 23:43:13 +01:00
|
|
|
|
{
|
2002-08-07 01:18:01 +02:00
|
|
|
|
if (function->lines)
|
|
|
|
|
fnotice (stdout, "%s of %d lines executed in %s %s\n",
|
|
|
|
|
format_hwint (function->lines_executed,
|
|
|
|
|
function->lines, 2),
|
|
|
|
|
function->lines, title, function->name);
|
1997-03-28 23:43:13 +01:00
|
|
|
|
else
|
2002-08-07 01:18:01 +02:00
|
|
|
|
fnotice (stdout, "No executable lines in %s %s\n",
|
|
|
|
|
title, function->name);
|
1997-03-28 23:43:13 +01:00
|
|
|
|
|
|
|
|
|
if (output_branch_probs)
|
|
|
|
|
{
|
2002-08-07 01:18:01 +02:00
|
|
|
|
if (function->branches)
|
1997-03-28 23:43:13 +01:00
|
|
|
|
{
|
2002-08-07 01:18:01 +02:00
|
|
|
|
fnotice (stdout, "%s of %d branches executed in %s %s\n",
|
|
|
|
|
format_hwint (function->branches_executed,
|
|
|
|
|
function->branches, 2),
|
|
|
|
|
function->branches, title, function->name);
|
1999-01-27 02:43:17 +01:00
|
|
|
|
fnotice (stdout,
|
2002-08-07 01:18:01 +02:00
|
|
|
|
"%s of %d branches taken at least once in %s %s\n",
|
|
|
|
|
format_hwint (function->branches_taken,
|
|
|
|
|
function->branches, 2),
|
|
|
|
|
function->branches, title, function->name);
|
1997-03-28 23:43:13 +01:00
|
|
|
|
}
|
|
|
|
|
else
|
2002-08-07 01:18:01 +02:00
|
|
|
|
fnotice (stdout, "No branches in %s %s\n", title, function->name);
|
|
|
|
|
if (function->calls)
|
|
|
|
|
fnotice (stdout, "%s of %d calls executed in %s %s\n",
|
|
|
|
|
format_hwint (function->calls_executed,
|
|
|
|
|
function->calls, 2),
|
|
|
|
|
function->calls, title, function->name);
|
1997-03-28 23:43:13 +01:00
|
|
|
|
else
|
2002-08-07 01:18:01 +02:00
|
|
|
|
fnotice (stdout, "No calls in %s %s\n", title, function->name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Generate an output file name. LONG_OUTPUT_NAMES and PRESERVE_PATHS
|
|
|
|
|
affect name generation. With preserve_paths we create a filename
|
|
|
|
|
from all path components of the source file, replacing '/' with
|
|
|
|
|
'#', without it we simply take the basename component. With
|
|
|
|
|
long_output_names we prepend the processed name of the input file
|
|
|
|
|
to each output name (except when the current source file is the
|
|
|
|
|
input file, so you don't get a double concatenation). The two
|
|
|
|
|
components are separated by '##'. Also '.' filename components are
|
2002-09-08 14:47:27 +02:00
|
|
|
|
removed and '..' components are renamed to '^'. */
|
2002-08-07 01:18:01 +02:00
|
|
|
|
|
|
|
|
|
static char *
|
|
|
|
|
make_gcov_file_name (src_name)
|
|
|
|
|
char *src_name;
|
|
|
|
|
{
|
|
|
|
|
char *cptr;
|
|
|
|
|
char *name = xmalloc (strlen (src_name) + strlen (input_file_name) + 10);
|
|
|
|
|
|
|
|
|
|
name[0] = 0;
|
|
|
|
|
if (output_long_names && strcmp (src_name, input_file_name))
|
|
|
|
|
{
|
|
|
|
|
/* Generate the input filename part. */
|
|
|
|
|
cptr = preserve_paths ? NULL : strrchr (input_file_name, '/');
|
|
|
|
|
cptr = cptr ? cptr + 1 : input_file_name;
|
|
|
|
|
strcat (name, cptr);
|
|
|
|
|
strcat (name, "##");
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-08 14:47:27 +02:00
|
|
|
|
/* Generate the source filename part. */
|
2002-08-07 01:18:01 +02:00
|
|
|
|
cptr = preserve_paths ? NULL : strrchr (src_name, '/');
|
|
|
|
|
cptr = cptr ? cptr + 1 : src_name;
|
|
|
|
|
strcat (name, cptr);
|
|
|
|
|
|
|
|
|
|
if (preserve_paths)
|
|
|
|
|
{
|
|
|
|
|
/* Convert '/' to '#', remove '/./', convert '/../' to '/^/' */
|
|
|
|
|
char *prev;
|
|
|
|
|
|
|
|
|
|
for (cptr = name; (cptr = strchr ((prev = cptr), '/'));)
|
|
|
|
|
{
|
|
|
|
|
unsigned shift = 0;
|
|
|
|
|
|
|
|
|
|
if (prev + 1 == cptr && prev[0] == '.')
|
|
|
|
|
{
|
|
|
|
|
/* Remove '.' */
|
|
|
|
|
shift = 2;
|
|
|
|
|
}
|
|
|
|
|
else if (prev + 2 == cptr && prev[0] == '.' && prev[1] == '.')
|
|
|
|
|
{
|
|
|
|
|
/* Convert '..' */
|
|
|
|
|
shift = 1;
|
|
|
|
|
prev[1] = '^';
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
*cptr++ = '#';
|
|
|
|
|
if (shift)
|
|
|
|
|
{
|
|
|
|
|
cptr = prev;
|
|
|
|
|
do
|
|
|
|
|
prev[0] = prev[shift];
|
|
|
|
|
while (*prev++);
|
|
|
|
|
}
|
|
|
|
|
}
|
1997-03-28 23:43:13 +01:00
|
|
|
|
}
|
2002-08-07 01:18:01 +02:00
|
|
|
|
|
|
|
|
|
/* Don't strip off the ending for compatibility with tcov, since
|
|
|
|
|
this results in confusion if there is more than one file with the
|
|
|
|
|
same basename, e.g. tmp.c and tmp.h. */
|
|
|
|
|
strcat (name, ".gcov");
|
|
|
|
|
return name;
|
1997-03-28 23:43:13 +01:00
|
|
|
|
}
|
|
|
|
|
|
2002-08-07 01:18:01 +02:00
|
|
|
|
/* Scan through the bb_data, and when the file name matches the
|
|
|
|
|
source file name, then for each following line number, increment
|
|
|
|
|
the line number execution count indicated by the execution count of
|
|
|
|
|
the appropriate basic block. */
|
1997-03-28 23:43:13 +01:00
|
|
|
|
|
|
|
|
|
static void
|
2002-08-07 01:18:01 +02:00
|
|
|
|
init_line_info (line_info, total, maxlineno)
|
|
|
|
|
struct line_info *line_info;
|
|
|
|
|
struct coverage *total;
|
|
|
|
|
long maxlineno;
|
1997-03-28 23:43:13 +01:00
|
|
|
|
{
|
2002-08-07 01:18:01 +02:00
|
|
|
|
long block_num = 0; /* current block number */
|
|
|
|
|
struct bb_info *block_ptr = NULL; /* current block ptr */
|
|
|
|
|
struct coverage function;
|
|
|
|
|
struct coverage *func_ptr = NULL;
|
2002-09-08 14:47:27 +02:00
|
|
|
|
struct bb_info_list *current_graph = NULL; /* Graph for current function. */
|
|
|
|
|
int is_this_file = 0; /* We're scanning a block from the desired file. */
|
2002-08-07 01:18:01 +02:00
|
|
|
|
char *ptr = bb_data;
|
2001-07-30 20:04:33 +02:00
|
|
|
|
long count;
|
1997-03-28 23:43:13 +01:00
|
|
|
|
long line_num;
|
2002-09-08 14:47:27 +02:00
|
|
|
|
struct line_info *line_ptr = 0; /* line info ptr. */
|
2002-08-07 01:18:01 +02:00
|
|
|
|
|
|
|
|
|
memset (&function, 0, sizeof (function));
|
|
|
|
|
if (output_function_summary)
|
|
|
|
|
func_ptr = &function;
|
|
|
|
|
|
|
|
|
|
for (count = 0; count < bb_data_size; count++)
|
1997-03-28 23:43:13 +01:00
|
|
|
|
{
|
2002-08-07 01:18:01 +02:00
|
|
|
|
__fetch_long (&line_num, ptr, 4);
|
|
|
|
|
ptr += 4;
|
|
|
|
|
if (line_num < 0)
|
1997-03-28 23:43:13 +01:00
|
|
|
|
{
|
2002-08-07 01:18:01 +02:00
|
|
|
|
long delim;
|
|
|
|
|
|
|
|
|
|
if (line_num == -1)
|
1997-03-28 23:43:13 +01:00
|
|
|
|
{
|
2002-08-07 01:18:01 +02:00
|
|
|
|
/* Marks the beginning of a file name. Check to see
|
|
|
|
|
whether this is the filename we are currently
|
|
|
|
|
collecting data for. */
|
|
|
|
|
is_this_file = !strcmp (total->name, ptr);
|
1997-03-28 23:43:13 +01:00
|
|
|
|
}
|
2002-08-07 01:18:01 +02:00
|
|
|
|
else if (line_num == -2)
|
1997-03-28 23:43:13 +01:00
|
|
|
|
{
|
2002-08-07 01:18:01 +02:00
|
|
|
|
/* Marks the start of a new function. Advance to the
|
|
|
|
|
next program flow graph. */
|
|
|
|
|
if (!current_graph)
|
|
|
|
|
current_graph = bb_graph_list;
|
|
|
|
|
else
|
1997-03-28 23:43:13 +01:00
|
|
|
|
{
|
2002-08-07 01:18:01 +02:00
|
|
|
|
if (block_num == current_graph->num_blocks - 1)
|
|
|
|
|
/* Last block falls through to exit. */
|
|
|
|
|
;
|
|
|
|
|
else if (block_num == current_graph->num_blocks - 2)
|
1997-03-28 23:43:13 +01:00
|
|
|
|
{
|
2002-08-07 01:18:01 +02:00
|
|
|
|
if (output_branch_probs && is_this_file)
|
|
|
|
|
calculate_branch_probs (block_ptr, line_ptr, func_ptr);
|
1997-03-28 23:43:13 +01:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2002-08-07 01:18:01 +02:00
|
|
|
|
fnotice (stderr,
|
|
|
|
|
"didn't use all bb entries of graph, function %s\n",
|
|
|
|
|
function.name);
|
|
|
|
|
fnotice (stderr, "block_num = %ld, num_blocks = %d\n",
|
|
|
|
|
block_num, current_graph->num_blocks);
|
1997-03-28 23:43:13 +01:00
|
|
|
|
}
|
2002-08-07 01:18:01 +02:00
|
|
|
|
if (func_ptr && is_this_file)
|
|
|
|
|
function_summary (func_ptr, "function");
|
|
|
|
|
current_graph = current_graph->next;
|
1997-03-28 23:43:13 +01:00
|
|
|
|
}
|
2002-08-07 01:18:01 +02:00
|
|
|
|
block_num = 0;
|
|
|
|
|
block_ptr = current_graph->bb_graph;
|
|
|
|
|
memset (&function, 0, sizeof (function));
|
|
|
|
|
function.name = ptr;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
fnotice (stderr, "ERROR: unexpected line number %ld\n", line_num);
|
|
|
|
|
abort ();
|
1997-03-28 23:43:13 +01:00
|
|
|
|
}
|
|
|
|
|
|
2002-08-07 01:18:01 +02:00
|
|
|
|
/* Scan past the string. */
|
|
|
|
|
for (delim = 0; delim != line_num; count++)
|
|
|
|
|
{
|
|
|
|
|
__fetch_long (&delim, ptr, 4);
|
|
|
|
|
ptr += 4;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (!line_num)
|
1997-03-28 23:43:13 +01:00
|
|
|
|
{
|
2002-08-07 01:18:01 +02:00
|
|
|
|
/* Marks the end of a block. */
|
|
|
|
|
if (block_num >= current_graph->num_blocks)
|
1997-03-28 23:43:13 +01:00
|
|
|
|
{
|
2002-08-07 01:18:01 +02:00
|
|
|
|
fnotice (stderr, "ERROR: too many basic blocks in function %s\n",
|
|
|
|
|
function.name);
|
|
|
|
|
abort ();
|
1997-03-28 23:43:13 +01:00
|
|
|
|
}
|
2002-08-07 01:18:01 +02:00
|
|
|
|
|
|
|
|
|
if (output_branch_probs && is_this_file)
|
|
|
|
|
calculate_branch_probs (block_ptr, line_ptr, func_ptr);
|
|
|
|
|
|
|
|
|
|
block_num++;
|
|
|
|
|
block_ptr++;
|
1997-03-28 23:43:13 +01:00
|
|
|
|
}
|
2002-08-07 01:18:01 +02:00
|
|
|
|
else if (is_this_file)
|
1997-03-28 23:43:13 +01:00
|
|
|
|
{
|
2002-08-07 01:18:01 +02:00
|
|
|
|
if (line_num >= maxlineno)
|
1997-03-28 23:43:13 +01:00
|
|
|
|
{
|
2002-08-07 01:18:01 +02:00
|
|
|
|
fnotice (stderr, "ERROR: out of range line number in function %s\n",
|
|
|
|
|
function.name);
|
|
|
|
|
abort ();
|
1997-03-28 23:43:13 +01:00
|
|
|
|
}
|
|
|
|
|
|
2002-08-07 01:18:01 +02:00
|
|
|
|
line_ptr = &line_info[line_num];
|
|
|
|
|
if (func_ptr)
|
1997-03-28 23:43:13 +01:00
|
|
|
|
{
|
2002-08-07 01:18:01 +02:00
|
|
|
|
if (!line_ptr->exists)
|
|
|
|
|
func_ptr->lines++;
|
|
|
|
|
if (!line_ptr->count && block_ptr->exec_count)
|
|
|
|
|
func_ptr->lines_executed++;
|
1997-03-28 23:43:13 +01:00
|
|
|
|
}
|
2002-08-04 19:06:10 +02:00
|
|
|
|
|
2002-08-07 01:18:01 +02:00
|
|
|
|
/* Accumulate execution data for this line number. */
|
|
|
|
|
line_ptr->count += block_ptr->exec_count;
|
|
|
|
|
line_ptr->exists = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (func_ptr && is_this_file)
|
|
|
|
|
function_summary (func_ptr, "function");
|
|
|
|
|
|
|
|
|
|
/* Calculate summary test coverage statistics. */
|
|
|
|
|
for (line_num = 1, line_ptr = &line_info[line_num];
|
|
|
|
|
line_num < maxlineno; line_num++, line_ptr++)
|
|
|
|
|
{
|
|
|
|
|
struct arcdata *a_ptr, *prev, *next;
|
|
|
|
|
|
|
|
|
|
if (line_ptr->exists)
|
|
|
|
|
{
|
|
|
|
|
total->lines++;
|
|
|
|
|
if (line_ptr->count)
|
|
|
|
|
total->lines_executed++;
|
|
|
|
|
}
|
1997-03-28 23:43:13 +01:00
|
|
|
|
|
2002-09-08 14:47:27 +02:00
|
|
|
|
/* Total and reverse the branch information. */
|
2002-08-07 01:18:01 +02:00
|
|
|
|
for (a_ptr = line_ptr->branches, prev = NULL; a_ptr; a_ptr = next)
|
|
|
|
|
{
|
|
|
|
|
next = a_ptr->next;
|
|
|
|
|
a_ptr->next = prev;
|
|
|
|
|
prev = a_ptr;
|
1997-03-28 23:43:13 +01:00
|
|
|
|
|
2002-08-07 01:18:01 +02:00
|
|
|
|
accumulate_branch_counts (total, a_ptr);
|
|
|
|
|
}
|
|
|
|
|
line_ptr->branches = prev;
|
|
|
|
|
}
|
|
|
|
|
}
|
1997-03-28 23:43:13 +01:00
|
|
|
|
|
2002-08-07 01:18:01 +02:00
|
|
|
|
/* Read in the source file one line at a time, and output that line to
|
|
|
|
|
the gcov file preceded by its execution count and other
|
|
|
|
|
information. */
|
1997-03-28 23:43:13 +01:00
|
|
|
|
|
2002-08-07 01:18:01 +02:00
|
|
|
|
static void
|
|
|
|
|
output_line_info (gcov_file, line_info, total, maxlineno)
|
|
|
|
|
FILE *gcov_file;
|
|
|
|
|
const struct line_info *line_info;
|
|
|
|
|
const struct coverage *total;
|
|
|
|
|
long maxlineno;
|
|
|
|
|
{
|
|
|
|
|
FILE *source_file;
|
|
|
|
|
long line_num; /* current line number */
|
2002-09-08 14:47:27 +02:00
|
|
|
|
const struct line_info *line_ptr; /* current line info ptr. */
|
|
|
|
|
char string[STRING_SIZE]; /* line buffer. */
|
|
|
|
|
char const *retval = ""; /* status of source file reading. */
|
1997-03-28 23:43:13 +01:00
|
|
|
|
|
2002-08-07 01:18:01 +02:00
|
|
|
|
fprintf (gcov_file, "%9s:%5d:Source:%s\n", "-", 0, total->name);
|
|
|
|
|
fprintf (gcov_file, "%9s:%5d:Object:%s\n", "-", 0, bb_file_name);
|
|
|
|
|
|
|
|
|
|
source_file = fopen (total->name, "r");
|
|
|
|
|
if (!source_file)
|
|
|
|
|
{
|
|
|
|
|
fnotice (stderr, "Could not open source file %s.\n", total->name);
|
|
|
|
|
retval = NULL;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
struct stat status;
|
|
|
|
|
|
|
|
|
|
if (!fstat (fileno (source_file), &status)
|
|
|
|
|
&& status.st_mtime > bb_file_time)
|
|
|
|
|
{
|
|
|
|
|
fnotice (stderr, "Warning: source file %s is newer than %s\n",
|
|
|
|
|
total->name, bb_file_name);
|
|
|
|
|
fprintf (gcov_file, "%9s:%5d:Source is newer than compiler output\n",
|
|
|
|
|
"-", 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (line_num = 1, line_ptr = &line_info[line_num];
|
|
|
|
|
line_num < maxlineno; line_num++, line_ptr++)
|
|
|
|
|
{
|
|
|
|
|
/* For lines which don't exist in the .bb file, print '-' before
|
|
|
|
|
the source line. For lines which exist but were never
|
|
|
|
|
executed, print '#####' before the source line. Otherwise,
|
|
|
|
|
print the execution count before the source line. There are
|
|
|
|
|
16 spaces of indentation added before the source line so that
|
|
|
|
|
tabs won't be messed up. */
|
|
|
|
|
fprintf (gcov_file, "%9s:%5ld:",
|
|
|
|
|
!line_ptr->exists ? "-"
|
|
|
|
|
: !line_ptr->count ? "#####"
|
|
|
|
|
: format_hwint (line_ptr->count, 0, -1), line_num);
|
|
|
|
|
|
|
|
|
|
if (retval)
|
|
|
|
|
{
|
|
|
|
|
/* Copy source line. */
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
retval = fgets (string, STRING_SIZE, source_file);
|
|
|
|
|
if (!retval)
|
2002-08-04 19:06:10 +02:00
|
|
|
|
{
|
2002-08-07 01:18:01 +02:00
|
|
|
|
fnotice (stderr,
|
|
|
|
|
"Unexpected EOF while reading source file %s.\n",
|
|
|
|
|
total->name);
|
|
|
|
|
break;
|
2002-08-04 19:06:10 +02:00
|
|
|
|
}
|
2002-08-07 01:18:01 +02:00
|
|
|
|
fputs (retval, gcov_file);
|
2002-08-04 19:06:10 +02:00
|
|
|
|
}
|
2002-08-07 01:18:01 +02:00
|
|
|
|
while (!retval[0] || retval[strlen (retval) - 1] != '\n');
|
|
|
|
|
}
|
|
|
|
|
if (!retval)
|
|
|
|
|
fputs ("??\n", gcov_file);
|
|
|
|
|
|
|
|
|
|
if (output_branch_probs)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
struct arcdata *a_ptr;
|
2002-08-04 19:06:10 +02:00
|
|
|
|
|
2002-08-07 01:18:01 +02:00
|
|
|
|
for (i = 0, a_ptr = line_ptr->branches; a_ptr;
|
|
|
|
|
a_ptr = a_ptr->next, i++)
|
2002-08-04 19:06:10 +02:00
|
|
|
|
{
|
2002-08-07 01:18:01 +02:00
|
|
|
|
if (a_ptr->call_insn)
|
1997-03-28 23:43:13 +01:00
|
|
|
|
{
|
2002-08-07 01:18:01 +02:00
|
|
|
|
if (a_ptr->total == 0)
|
|
|
|
|
fnotice (gcov_file, "call %2d never executed\n", i);
|
|
|
|
|
else
|
|
|
|
|
fnotice
|
|
|
|
|
(gcov_file, "call %2d returns %s\n", i,
|
|
|
|
|
format_hwint (a_ptr->total - a_ptr->hits,
|
|
|
|
|
a_ptr->total,
|
|
|
|
|
-output_branch_counts));
|
1997-03-28 23:43:13 +01:00
|
|
|
|
}
|
2002-08-07 01:18:01 +02:00
|
|
|
|
else
|
1997-03-28 23:43:13 +01:00
|
|
|
|
{
|
2002-08-07 01:18:01 +02:00
|
|
|
|
if (a_ptr->total == 0)
|
|
|
|
|
fnotice (gcov_file, "branch %2d never executed\n", i);
|
|
|
|
|
else
|
|
|
|
|
fnotice
|
|
|
|
|
(gcov_file, "branch %2d taken %s\n", i,
|
|
|
|
|
format_hwint (a_ptr->hits, a_ptr->total,
|
|
|
|
|
-output_branch_counts));
|
|
|
|
|
}
|
1997-03-28 23:43:13 +01:00
|
|
|
|
}
|
2002-08-07 01:18:01 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Handle all remaining source lines. There may be lines after the
|
|
|
|
|
last line of code. */
|
|
|
|
|
if (retval)
|
|
|
|
|
{
|
|
|
|
|
for (; (retval = fgets (string, STRING_SIZE, source_file)); line_num++)
|
|
|
|
|
{
|
|
|
|
|
fprintf (gcov_file, "%9s:%5ld:%s", "-", line_num, retval);
|
|
|
|
|
|
|
|
|
|
while (!retval[0] || retval[strlen (retval) - 1] != '\n')
|
2002-08-04 19:06:10 +02:00
|
|
|
|
{
|
2002-08-07 01:18:01 +02:00
|
|
|
|
retval = fgets (string, STRING_SIZE, source_file);
|
|
|
|
|
if (!retval)
|
|
|
|
|
break;
|
|
|
|
|
fputs (retval, gcov_file);
|
2002-08-04 19:06:10 +02:00
|
|
|
|
}
|
2002-08-07 01:18:01 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (source_file)
|
|
|
|
|
fclose (source_file);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Calculate line execution counts, and output a .gcov file for source
|
|
|
|
|
file S_PTR. Allocate an array big enough to hold a count for each
|
|
|
|
|
line. Scan through the bb_data, and when the file name matches the
|
|
|
|
|
current file name, then for each following line number, increment
|
|
|
|
|
the line number execution count indicated by the execution count of
|
|
|
|
|
the appropriate basic block. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
output_data (s_ptr)
|
|
|
|
|
struct sourcefile *s_ptr;
|
|
|
|
|
{
|
|
|
|
|
struct line_info *line_info /* line info data */
|
|
|
|
|
= (struct line_info *) xcalloc (s_ptr->maxlineno,
|
|
|
|
|
sizeof (struct line_info));
|
|
|
|
|
long line_num;
|
|
|
|
|
struct coverage total;
|
|
|
|
|
|
|
|
|
|
memset (&total, 0, sizeof (total));
|
|
|
|
|
total.name = s_ptr->name;
|
|
|
|
|
|
|
|
|
|
init_line_info (line_info, &total, s_ptr->maxlineno);
|
|
|
|
|
function_summary (&total, "file");
|
1997-03-28 23:43:13 +01:00
|
|
|
|
|
2002-08-07 01:18:01 +02:00
|
|
|
|
if (output_gcov_file)
|
|
|
|
|
{
|
|
|
|
|
/* Now the statistics are ready. Read in the source file one
|
|
|
|
|
line at a time, and output that line to the gcov file
|
|
|
|
|
preceded by its execution information. */
|
|
|
|
|
|
|
|
|
|
char *gcov_file_name = make_gcov_file_name (total.name);
|
|
|
|
|
FILE *gcov_file = fopen (gcov_file_name, "w");
|
|
|
|
|
|
|
|
|
|
if (gcov_file)
|
|
|
|
|
{
|
|
|
|
|
fnotice (stdout, "Creating %s.\n", gcov_file_name);
|
|
|
|
|
output_line_info (gcov_file, line_info, &total, s_ptr->maxlineno);
|
2002-08-04 19:06:10 +02:00
|
|
|
|
if (ferror (gcov_file))
|
|
|
|
|
fnotice (stderr, "Error writing output file %s.\n",
|
|
|
|
|
gcov_file_name);
|
1997-03-28 23:43:13 +01:00
|
|
|
|
fclose (gcov_file);
|
|
|
|
|
}
|
2002-08-07 01:18:01 +02:00
|
|
|
|
else
|
|
|
|
|
fnotice (stderr, "Could not open output file %s.\n", gcov_file_name);
|
|
|
|
|
free (gcov_file_name);
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-08 14:47:27 +02:00
|
|
|
|
/* Free data. */
|
2002-08-07 01:18:01 +02:00
|
|
|
|
for (line_num = 1; line_num != s_ptr->maxlineno; line_num++)
|
|
|
|
|
{
|
|
|
|
|
struct arcdata *branch, *next;
|
1997-03-28 23:43:13 +01:00
|
|
|
|
|
2002-08-07 01:18:01 +02:00
|
|
|
|
for (branch = line_info[line_num].branches; branch; branch = next)
|
|
|
|
|
{
|
|
|
|
|
next = branch->next;
|
|
|
|
|
free (branch);
|
|
|
|
|
}
|
1997-03-28 23:43:13 +01:00
|
|
|
|
}
|
2002-08-07 01:18:01 +02:00
|
|
|
|
free (line_info);
|
1997-03-28 23:43:13 +01:00
|
|
|
|
}
|