This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

cfg merge part 14-1 new profiler format


Hi,
this patch splits out the profiler format changes from the thread safety patch,
so they can be dealt independently.  Hope it will make the review process
easier.

Note that I have some plans about minor changes in the format - it consist of
the header and set of records identified by the function name containing
counters and checksum from various runs of the program.  The header has
extension block, where we can put extra data.  I would like the records
to contain IDs as well, so we can add more than just the counters,
for example loop iteration count histograms in the future.

I have finals in three weeks from now, so I would like to do this afterwards.

Mon May  6 15:48:50 CEST 2002  Jan Hubicka  <jh@suse.cz>
			       Pavel Nejedly  <bim@atrey.karlin.mff.cuni.cz>

	* final.c (end_final): Use C trees to output data structures for profiling.

	* Makefile.in (LIBGCC_DEPS): Added missing dependency on gcov-io.h
        (profile.o): New dependency profile.h
        (final.o): New dependency profile.h
        * profile.h: New file. New global structure profile_info.
        * final.h (count_edges_instrumented_now): Declare.
        (current_function_cfg_checksum): Declare.
        (function_list): New structure.
        (functions_head, functions_tail): New static variables.
        (end_final): Emits more data, removed some -ax stuff.
        (final): Stores function names and chcksums.
        * gcov-io.h (__write_gcov_string): New function.
        (__read_gcov_string): New function.
        * gcov.c (read_profile): New function.
        (create_program_flow_graph): Uses read_profile instead of reading
	da_file.
        (read_files): Removed da_file checking, it's done by read_profile now.
        * libgcc2.c (bb_function_info): New structure.
        (bb): New field in structure, removed some -ax stuff.
        (__bb_exit_func): Changed structure of da_file.
        * profile.c (count_edges_instrumented_now): New global variable.
        (current_function_cfg_checksum): New global variable.
        (max_counter_in_program): New global variable.
        (get_exec_counts): New function.
        (compute_checksum): New function.
        (instrument_edges): Sets count_edges_instrumented_now.
        (compute_branch_probabilities): Uses get_exec_counts instead of
	reading da_file.
        (branch_prob): Calls compute_checksum and writes extra data to bbg_file.
        (init_branch_prob): Removed da_file checking, done in get_exec_counts
	now.
        (end_branch_prob): Removed da_file checking, done in get_exec_counts
	now.
        * gcov.texi: Updated information about gcov file format.

Index: Makefile.in
===================================================================
RCS file: /cvs/gcc/egcs/gcc/Makefile.in,v
retrieving revision 1.867
diff -c -3 -p -r1.867 Makefile.in
*** Makefile.in	8 May 2002 09:17:15 -0000	1.867
--- Makefile.in	8 May 2002 10:10:25 -0000
*************** conflict.o : conflict.c $(CONFIG_H) $(SY
*** 1484,1490 ****
  profile.o : profile.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h \
     insn-config.h output.h $(REGS_H) $(EXPR_H) function.h \
     gcov-io.h toplev.h $(GGC_H) hard-reg-set.h $(BASIC_BLOCK_H) $(TARGET_H) \
!    langhooks.h
  loop.o : loop.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) flags.h $(LOOP_H) \
     insn-config.h $(REGS_H) hard-reg-set.h $(RECOG_H) $(EXPR_H) \
     real.h $(PREDICT_H) $(BASIC_BLOCK_H) function.h \
--- 1484,1490 ----
  profile.o : profile.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h \
     insn-config.h output.h $(REGS_H) $(EXPR_H) function.h \
     gcov-io.h toplev.h $(GGC_H) hard-reg-set.h $(BASIC_BLOCK_H) $(TARGET_H) \
!    langhooks.h profile.h libfuncs.h
  loop.o : loop.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) flags.h $(LOOP_H) \
     insn-config.h $(REGS_H) hard-reg-set.h $(RECOG_H) $(EXPR_H) \
     real.h $(PREDICT_H) $(BASIC_BLOCK_H) function.h \
*************** sched-vis.o : sched-vis.c $(CONFIG_H) $(
*** 1568,1574 ****
     $(TARGET_H) real.h
  final.o : final.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h intl.h \
     $(REGS_H) $(RECOG_H) conditions.h insn-config.h $(INSN_ATTR_H) function.h \
!    real.h output.h hard-reg-set.h except.h debug.h xcoffout.h \
     toplev.h reload.h dwarf2out.h $(BASIC_BLOCK_H) $(TM_P_H) $(TARGET_H) $(EXPR_H)
  recog.o : recog.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) function.h $(BASIC_BLOCK_H) \
     $(REGS_H) $(RECOG_H) $(EXPR_H) hard-reg-set.h flags.h insn-config.h \
--- 1568,1574 ----
     $(TARGET_H) real.h
  final.o : final.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h intl.h \
     $(REGS_H) $(RECOG_H) conditions.h insn-config.h $(INSN_ATTR_H) function.h \
!    real.h output.h hard-reg-set.h except.h debug.h xcoffout.h profile.h \
     toplev.h reload.h dwarf2out.h $(BASIC_BLOCK_H) $(TM_P_H) $(TARGET_H) $(EXPR_H)
  recog.o : recog.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) function.h $(BASIC_BLOCK_H) \
     $(REGS_H) $(RECOG_H) $(EXPR_H) hard-reg-set.h flags.h insn-config.h \
Index: final.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/final.c,v
retrieving revision 1.247
diff -c -3 -p -r1.247 final.c
*** final.c	23 Apr 2002 07:20:50 -0000	1.247
--- final.c	8 May 2002 10:10:28 -0000
*************** Software Foundation, 59 Temple Place - S
*** 68,73 ****
--- 68,74 ----
  #include "target.h"
  #include "debug.h"
  #include "expr.h"
+ #include "profile.h"
  
  #ifdef XCOFF_DEBUGGING_INFO
  #include "xcoffout.h"		/* Needed for external data
*************** static int high_function_linenum;
*** 114,122 ****
  /* Filename of last NOTE.  */
  static const char *last_filename;
  
- /* Number of instrumented arcs when profile_arc_flag is set.  */
- extern int count_instrumented_edges;
- 
  extern int length_unit_log; /* This is defined in insn-attrtab.c.  */
  
  /* Nonzero while outputting an `asm' with operands.
--- 115,120 ----
*************** static char *line_note_exists;
*** 198,203 ****
--- 196,212 ----
  rtx current_insn_predicate;
  #endif
  
+ struct function_list
+ {
+   struct function_list *next; 	/* next function */
+   const char *name; 		/* function name */
+   long cfg_checksum;		/* function checksum */
+   long count_edges;		/* number of intrumented edges in this function */
+ };
+ 
+ static struct function_list *functions_head = 0;
+ static struct function_list **functions_tail = &functions_head;
+ 
  #ifdef HAVE_ATTR_length
  static int asm_insn_count	PARAMS ((rtx));
  #endif
*************** init_final (filename)
*** 237,243 ****
  }
  
  /* Called at end of source file,
!    to output the block-profiling table for this entire compilation.  */
  
  void
  end_final (filename)
--- 246,252 ----
  }
  
  /* Called at end of source file,
!    to output the arc-profiling table for this entire compilation.  */
  
  void
  end_final (filename)
*************** end_final (filename)
*** 246,373 ****
    if (profile_arc_flag)
      {
        char name[20];
!       int align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT);
!       int size, rounded;
!       int long_bytes = LONG_TYPE_SIZE / BITS_PER_UNIT;
!       int gcov_type_bytes = GCOV_TYPE_SIZE / BITS_PER_UNIT;
!       int pointer_bytes = POINTER_SIZE / BITS_PER_UNIT;
!       unsigned int align2 = LONG_TYPE_SIZE;
! 
!       size = gcov_type_bytes * count_instrumented_edges;
!       rounded = size;
! 
!       rounded += (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1;
!       rounded = (rounded / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)
! 		 * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
! 
!       /* ??? This _really_ ought to be done with a structure layout
! 	 and with assemble_constructor.  If long_bytes != pointer_bytes
! 	 we'll be emitting unaligned data at some point.  */
!       if (long_bytes != pointer_bytes)
! 	abort ();
! 
!       data_section ();
! 
!       /* Output the main header, of 11 words:
! 	 0:  1 if this file is initialized, else 0.
! 	 1:  address of file name (LPBX1).
! 	 2:  address of table of counts (LPBX2).
! 	 3:  number of counts in the table.
! 	 4:  always 0, for compatibility with Sun.
  
           The following are GNU extensions:
  
! 	 5:  address of table of start addrs of basic blocks (LPBX3).
! 	 6:  Number of bytes in this header.
! 	 7:  address of table of function names (LPBX4).
! 	 8:  address of table of line numbers (LPBX5) or 0.
! 	 9:  address of table of file names (LPBX6) or 0.
! 	10:  space reserved for basic block profiling.  */
  
!       ASM_OUTPUT_ALIGN (asm_out_file, align);
  
!       ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 0);
  
!       /* Zero word.  */
!       assemble_integer (const0_rtx, long_bytes, align2, 1);
  
!       /* Address of filename.  */
!       ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 1);
!       assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes,
! 			align2, 1);
! 
!       /* Address of count table.  */
!       ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 2);
!       assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes,
! 			align2, 1);
  
        /* Count of the # of instrumented arcs.  */
!       assemble_integer (GEN_INT (count_instrumented_edges),
! 			long_bytes, align2, 1);
  
!       /* Zero word (link field).  */
!       assemble_integer (const0_rtx, pointer_bytes, align2, 1);
  
!       assemble_integer (const0_rtx, pointer_bytes, align2, 1);
  
!       /* Byte count for extended structure.  */
!       assemble_integer (GEN_INT (11 * UNITS_PER_WORD), long_bytes, align2, 1);
  
-       /* Address of function name table.  */
-       assemble_integer (const0_rtx, pointer_bytes, align2, 1);
  
!       /* Address of line number and filename tables if debugging.  */
!       assemble_integer (const0_rtx, pointer_bytes, align2, 1);
!       assemble_integer (const0_rtx, pointer_bytes, align2, 1);
  
!       /* Space for extension ptr (link field).  */
!       assemble_integer (const0_rtx, UNITS_PER_WORD, align2, 1);
  
!       /* Output the file name changing the suffix to .d for
! 	 Sun tcov compatibility.  */
!       ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 1);
        {
! 	char *cwd = getpwd ();
! 	int len = strlen (filename) + strlen (cwd) + 1;
! 	char *data_file = (char *) alloca (len + 4);
! 
! 	strcpy (data_file, cwd);
! 	strcat (data_file, "/");
! 	strcat (data_file, filename);
! 	strip_off_ending (data_file, len);
! 	strcat (data_file, ".da");
! 	assemble_string (data_file, strlen (data_file) + 1);
        }
- 
-       /* Make space for the table of counts.  */
-       if (size == 0)
- 	{
- 	  /* Realign data section.  */
- 	  ASM_OUTPUT_ALIGN (asm_out_file, align);
- 	  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 2);
- 	  if (size != 0)
- 	    assemble_zeros (size);
- 	}
-       else
- 	{
- 	  ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 2);
- #ifdef ASM_OUTPUT_SHARED_LOCAL
- 	  if (flag_shared_data)
- 	    ASM_OUTPUT_SHARED_LOCAL (asm_out_file, name, size, rounded);
- 	  else
- #endif
- #ifdef ASM_OUTPUT_ALIGNED_DECL_LOCAL
- 	    ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, NULL_TREE, name,
- 					   size, BIGGEST_ALIGNMENT);
- #else
- #ifdef ASM_OUTPUT_ALIGNED_LOCAL
- 	    ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size,
- 				      BIGGEST_ALIGNMENT);
- #else
- 	    ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
- #endif
- #endif
- 	}
      }
  }
  
--- 255,520 ----
    if (profile_arc_flag)
      {
        char name[20];
!       tree string_type, string_cst;
!       tree structure_decl, structure_value, structure_pointer_type;
!       tree field_decl, decl_chain, value_chain;
!       tree nwords_field_value, domain_type;
! 
!       /* Build types.  */
!       string_type = build_pointer_type (char_type_node);
! 
!       /* Libgcc2 bb structure.  */
!       structure_decl = make_node (RECORD_TYPE);
!       TYPE_PACKED (structure_decl) = flag_pack_struct;
!       structure_pointer_type = build_pointer_type (structure_decl);
! 
!       /* Output the main header, of 7 words:
!          0:  1 if this file is initialized, else 0.
!          1:  address of file name (LPBX1).
!          2:  address of table of counts (LPBX2).
!          3:  number of counts in the table.
!          4:  always 0, libgcc2 uses this as a pointer to next ``struct bb''
  
           The following are GNU extensions:
  
!          5:  Number of bytes in this header.
!          6:  address of table of function checksums (LPBX7).  */
  
!       /* The zero word.  */
!       decl_chain =
! 	build_decl (FIELD_DECL, get_identifier ("zero_word"),
! 		    long_integer_type_node);
!       value_chain = build_tree_list (decl_chain, integer_zero_node);
  
!       /* Address of filename.  */
!       {
! 	char *cwd = getpwd ();
! 	int da_filename_len = strlen (filename) + strlen (cwd) + 4 + 1;
! 	char *da_filename = (char *) alloca (da_filename_len);
  
! 	strcpy (da_filename, cwd);
! 	strcat (da_filename, "/");
! 	strcat (da_filename, filename);
! 	strip_off_ending (da_filename, da_filename_len - 3);
! 	strcat (da_filename, ".da");
! 	field_decl =
! 	  build_decl (FIELD_DECL, get_identifier ("filename"), string_type);
! 	string_cst = build_string (strlen (da_filename) + 1, da_filename);
! 	domain_type = build_index_type (build_int_2 (strlen (da_filename) + 1,
! 						     0));
! 	TREE_TYPE (string_cst) =
! 	  build_array_type (char_type_node, domain_type);
! 	value_chain = tree_cons (field_decl,
! 				 build1 (ADDR_EXPR, string_type, string_cst),
! 				 value_chain);
! 	TREE_CHAIN (field_decl) = decl_chain;
! 	decl_chain = field_decl;
!       }
  
!       /* Table of counts.  */
!       {
! 	tree gcov_type_type = make_unsigned_type (GCOV_TYPE_SIZE);
! 	tree gcov_type_pointer_type = build_pointer_type (gcov_type_type);
! 	tree gcov_type_array_type, gcov_type_array_pointer_type;
! 	tree domain_tree = build_index_type (build_int_2
! 					     (profile_info.
! 					      count_instrumented_edges - 1,
! 					      0));
! 	tree counts_table;
! 
! 	gcov_type_array_type = build_array_type (gcov_type_type, domain_tree);
! 	gcov_type_array_pointer_type =
! 	  build_pointer_type (gcov_type_array_type);
! 
! 	/* No values.  */
! 	counts_table =
! 	  build (VAR_DECL, gcov_type_array_type, NULL_TREE, NULL_TREE);
! 	TREE_STATIC (counts_table) = 1;
! 	ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 2);
! 	DECL_NAME (counts_table) = get_identifier (name);
! 	assemble_variable (counts_table, 0, 0, 0);
! 
! 	field_decl =
! 	  build_decl (FIELD_DECL, get_identifier ("counts"),
! 		      gcov_type_pointer_type);
! 	value_chain = tree_cons (field_decl,
! 				 build1 (ADDR_EXPR,
! 					 gcov_type_array_pointer_type,
! 					 counts_table), value_chain);
! 	TREE_CHAIN (field_decl) = decl_chain;
! 	decl_chain = field_decl;
!       }
  
        /* Count of the # of instrumented arcs.  */
!       field_decl =
! 	build_decl (FIELD_DECL, get_identifier ("ncounts"),
! 		    long_integer_type_node);
!       value_chain = tree_cons (field_decl,
! 			       build_int_2 (profile_info.
! 					    count_instrumented_edges, 0),
! 			       value_chain);
!       TREE_CHAIN (field_decl) = decl_chain;
!       decl_chain = field_decl;
! 
!       /* Pointer to the next bb.  */
!       field_decl =
! 	build_decl (FIELD_DECL, get_identifier ("next"),
! 		    structure_pointer_type);
!       value_chain = tree_cons (field_decl, null_pointer_node, value_chain);
!       TREE_CHAIN (field_decl) = decl_chain;
!       decl_chain = field_decl;
! 
!       /* Number of words. We'll set this after entire structure is laid out.  */
!       field_decl =
! 	build_decl (FIELD_DECL, get_identifier ("nwords"),
! 		    long_integer_type_node);
!       value_chain = nwords_field_value =
! 	tree_cons (field_decl, NULL, value_chain);
!       TREE_CHAIN (field_decl) = decl_chain;
!       decl_chain = field_decl;
  
!       /* struct bb_function [].  */
!       {
! 	struct function_list *item;
! 	int num_nodes;
! 	tree checksum_field, arc_count_field, name_field;
! 	tree domain;
! 	tree array_value_chain = NULL_TREE;
! 	tree bb_fn_struct_type;
! 	tree bb_fn_struct_array_type;
! 	tree bb_fn_struct_array_pointer_type;
! 	tree bb_fn_struct_pointer_type;
! 	tree field_value, field_value_chain;
! 
! 	bb_fn_struct_type = make_node (RECORD_TYPE);
! 	TYPE_PACKED (bb_fn_struct_type) = flag_pack_struct;
! 
! 	checksum_field = build_decl (FIELD_DECL, get_identifier ("checksum"),
! 				     long_integer_type_node);
! 	arc_count_field =
! 	  build_decl (FIELD_DECL, get_identifier ("arc_count"),
! 		      integer_type_node);
! 	TREE_CHAIN (checksum_field) = arc_count_field;
! 	name_field =
! 	  build_decl (FIELD_DECL, get_identifier ("name"), string_type);
! 	TREE_CHAIN (arc_count_field) = name_field;
! 
! 	TYPE_FIELDS (bb_fn_struct_type) = checksum_field;
! 
! 	num_nodes = 0;
! 
! 	for (item = functions_head; item != 0; item = item->next)
! 	  num_nodes++;
! 
! 	domain = make_node (INTEGER_TYPE);
! 	TYPE_MIN_VALUE (domain) = integer_zero_node;
! 	/* Note that the array contains a terminator, hence no - 1.  */
! 	TYPE_MAX_VALUE (domain) = build_int_2 (num_nodes, 0);
! 
! 	bb_fn_struct_pointer_type = build_pointer_type (bb_fn_struct_type);
! 	bb_fn_struct_array_type = build_array_type (bb_fn_struct_type,
! 						    domain);
! 	bb_fn_struct_array_pointer_type =
! 	  build_pointer_type (bb_fn_struct_array_type);
! 
! 	layout_type (bb_fn_struct_type);
! 	layout_type (bb_fn_struct_pointer_type);
! 	layout_type (bb_fn_struct_array_type);
! 	layout_type (bb_fn_struct_array_pointer_type);
  
! 	for (item = functions_head; item != 0; item = item->next)
! 	  {
! 	    /* create constructor for structure.  */
! 	    field_value_chain = build_tree_list (checksum_field,
! 						 build_int_2 (item->
! 							      cfg_checksum,
! 							      0));
! 	    field_value_chain =
! 	      tree_cons (arc_count_field, build_int_2 (item->count_edges, 0),
! 			 field_value_chain);
! 
! 	    string_cst = build_string (strlen (item->name) + 1, item->name);
! 	    domain_type = build_index_type (build_int_2 (strlen (item->name) +
! 							 1, 0));
! 	    TREE_TYPE (string_cst) = build_array_type (char_type_node,
! 						       domain_type);
! 	    field_value_chain = tree_cons (name_field,
! 					   build1 (ADDR_EXPR, string_type,
! 						   string_cst),
! 					   field_value_chain);
! 
! 	    /* Add to chain.  */
! 
! 	    array_value_chain = tree_cons (NULL_TREE,
! 					   build (CONSTRUCTOR,
! 						  bb_fn_struct_type,
! 						  NULL_TREE,
! 						  nreverse
! 						  (field_value_chain)),
! 					   array_value_chain);
! 	  }
  
! 	/* Add terminator.  */
! 	field_value = make_node (TREE_LIST);
! 	TREE_TYPE (field_value) = integer_type_node;
! 	TREE_PURPOSE (field_value) = arc_count_field;
! 	TREE_VALUE (field_value) = build_int_2 (-1, 0);
! 
! 	array_value_chain = tree_cons (NULL_TREE,
! 				       build (CONSTRUCTOR, bb_fn_struct_type,
! 					      NULL_TREE, field_value),
! 				       array_value_chain);
! 
! 
! 	/* Create constructor for array.  */
! 
! 	field_decl =
! 	  build_decl (FIELD_DECL, get_identifier ("function_infos"),
! 		      bb_fn_struct_pointer_type);
! 	value_chain = tree_cons (field_decl,
! 				 build1 (ADDR_EXPR,
! 					 bb_fn_struct_array_pointer_type,
! 					 build (CONSTRUCTOR,
! 						bb_fn_struct_array_type,
! 						NULL_TREE,
! 						nreverse
! 						(array_value_chain))),
! 				 value_chain);
! 	TREE_CHAIN (field_decl) = decl_chain;
! 	decl_chain = field_decl;
!       }
  
  
!       /* Finish structure.  */
!       TYPE_FIELDS (structure_decl) = nreverse (decl_chain);
!       layout_type (structure_decl);
! 
!       structure_value =
! 	build (VAR_DECL, structure_decl, NULL_TREE, NULL_TREE);
!       DECL_INITIAL (structure_value) =
! 	build (CONSTRUCTOR, structure_decl, NULL_TREE,
! 	       nreverse (value_chain));
!       TREE_STATIC (structure_value) = 1;
!       ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 0);
!       DECL_NAME (structure_value) = get_identifier (name);
! 
!       /* Set number of words in this structure. */
!       TREE_VALUE (nwords_field_value) =
! 	build_int_2 (TREE_INT_CST_LOW (TYPE_SIZE_UNIT (structure_decl)) /
! 		     (INT_TYPE_SIZE / BITS_PER_UNIT), 0);
  
!       /* Build structure.  */
!       assemble_variable (structure_value, 0, 0, 0);
  
!       /* Offset to table of arc counters for thread-safe profiling.  */
        {
! 	tree table_offset_var = make_node (VAR_DECL);
! 	TREE_TYPE (table_offset_var) = build_pointer_type (integer_type_node);
! 	DECL_INITIAL (table_offset_var) = integer_zero_node;
! 	DECL_NAME (table_offset_var) = get_identifier (".LPBF0");
! 	TREE_STATIC (table_offset_var) = 1;
! 	assemble_variable (table_offset_var, 0, 0, 0);
        }
      }
  }
  
*************** final (first, file, optimize, prescan)
*** 1781,1786 ****
--- 1928,1951 ----
        insn = final_scan_insn (insn, file, optimize, prescan, 0);
      }
  
+   /* Store function names for edge-profiling.  */
+ 
+   if (profile_arc_flag)
+   {
+     struct function_list *new_item = xmalloc (sizeof (struct function_list));
+ 
+     /* Add function to linked list.  */
+     new_item->next = 0;
+     *functions_tail = new_item;
+     functions_tail = &new_item->next;
+ 
+     /* Set values.  */
+     new_item->cfg_checksum = profile_info.current_function_cfg_checksum;
+     new_item->count_edges = profile_info.count_edges_instrumented_now;
+     new_item->name = xstrdup (current_function_name);
+     
+   }
+   
    free (line_note_exists);
    line_note_exists = NULL;
  }
Index: function.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/function.c,v
retrieving revision 1.362
diff -c -3 -p -r1.362 function.c
*** function.c	3 May 2002 00:23:55 -0000	1.362
--- function.c	8 May 2002 10:10:32 -0000
*************** prepare_function_start ()
*** 6318,6323 ****
--- 6318,6325 ----
  
    current_function_outgoing_args_size = 0;
  
+   cfun->arc_profile = profile_arc_flag || flag_test_coverage;
+ 
    (*lang_hooks.function.init) (cfun);
    if (init_machine_status)
      (*init_machine_status) (cfun);
Index: function.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/function.h,v
retrieving revision 1.78
diff -c -3 -p -r1.78 function.h
*** function.h	23 Apr 2002 07:20:51 -0000	1.78
--- function.h	8 May 2002 10:10:32 -0000
*************** struct function
*** 437,442 ****
--- 437,445 ----
       generated.  */
    unsigned int instrument_entry_exit : 1;
  
+   /* Nonzero if no profiling should be done for the function.  */
+   unsigned int arc_profile : 1;
+ 
    /* Nonzero if profiling code should be generated.  */
    unsigned int profile : 1;
  
Index: gcov-io.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/gcov-io.h,v
retrieving revision 1.14
diff -c -3 -p -r1.14 gcov-io.h
*** gcov-io.h	9 Oct 2001 14:03:11 -0000	1.14
--- gcov-io.h	8 May 2002 10:10:32 -0000
*************** Software Foundation, 59 Temple Place - S
*** 24,36 ****
  #include <stdio.h>
  #include <sys/types.h>
  
! static int __fetch_long	PARAMS ((long *, char *, size_t)) ATTRIBUTE_UNUSED;
! static int __read_long  PARAMS ((long *, FILE *, size_t)) ATTRIBUTE_UNUSED;
! static int __write_long PARAMS ((long, FILE *, size_t)) ATTRIBUTE_UNUSED;
! static int __fetch_gcov_type PARAMS ((gcov_type *, char *, size_t)) ATTRIBUTE_UNUSED;
! static int __store_gcov_type PARAMS ((gcov_type, char *, size_t)) ATTRIBUTE_UNUSED;
! static int __read_gcov_type  PARAMS ((gcov_type *, FILE *, size_t)) ATTRIBUTE_UNUSED;
! static int __write_gcov_type PARAMS ((gcov_type, FILE *, size_t)) ATTRIBUTE_UNUSED;
  
  /* These routines only work for signed values.  */
  
--- 24,47 ----
  #include <stdio.h>
  #include <sys/types.h>
  
! static int __fetch_long	PARAMS ((long *, char *, size_t))
! 	ATTRIBUTE_UNUSED;
! static int __read_long  PARAMS ((long *, FILE *, size_t))
! 	ATTRIBUTE_UNUSED;
! static int __write_long PARAMS ((long, FILE *, size_t))
! 	ATTRIBUTE_UNUSED;
! static int __fetch_gcov_type PARAMS ((gcov_type *, char *, size_t))
! 	ATTRIBUTE_UNUSED;
! static int __store_gcov_type PARAMS ((gcov_type, char *, size_t))
! 	ATTRIBUTE_UNUSED;
! static int __read_gcov_type  PARAMS ((gcov_type *, FILE *, size_t))
! 	ATTRIBUTE_UNUSED;
! static int __write_gcov_type PARAMS ((gcov_type, FILE *, size_t))
! 	ATTRIBUTE_UNUSED;
! static int __write_gcov_string PARAMS ((const char *, size_t, FILE*, long))
! 	ATTRIBUTE_UNUSED;
! static int __read_gcov_string PARAMS ((char *, size_t, FILE*, long))
! 	ATTRIBUTE_UNUSED;
  
  /* These routines only work for signed values.  */
  
*************** __read_long (dest, file, bytes)
*** 192,196 ****
--- 203,297 ----
    else
      return __fetch_long (dest, c, bytes);
  }
+ 
+ 
+ /* Writes string in gcov format.  */
+ 
+ static int
+ __write_gcov_string (string, length, file, delim)
+      const char *string;
+      size_t length;
+      FILE *file;
+      long delim;
+ {
+   size_t temp = length + 1;
+ 
+   /* delimiter */
+   if (__write_long (delim, file, 4) != 0)
+     return 1;
+ 
+   if (__write_long (length, file, 4) != 0)
+     return 1;
+ 
+   if (fwrite (string, temp, 1, file) != 1)
+     return 1;
+ 
+   temp &= 3;
+ 
+   if (temp)
+     {
+       char c[4];
+ 
+       c[0] = c[1] = c[2] = c[3] = 0;
+ 
+       if (fwrite (c, sizeof (char), 4 - temp, file) != 4 - temp)
+ 	return 1;
+     }
+ 
+   if (__write_long (delim, file, 4) != 0)
+     return 1;
+ 
+   return 0;
+ }
+ 
+ /* Reads string in gcov format.  */
+ 
+ 
+ static int
+ __read_gcov_string (string, max_length, file, delim)
+      char *string;
+      size_t max_length;
+      FILE *file;
+      long delim;
+ {
+   long delim_from_file;
+   long length;
+   long read_length;
+   long tmp;
+ 
+   if (__read_long (&delim_from_file, file, 4) != 0)
+     return 1;
+ 
+   if (delim_from_file != delim)
+     return 1;
+ 
+   if (__read_long (&length, file, 4) != 0)
+     return 1;
+ 
+   if (length > (long) max_length)
+     read_length = max_length;
+   else
+     read_length = length;
+ 
+   tmp = (((length + 1) - 1) / 4 + 1) * 4;
+   /* This is the size occupied by the string in the file */
+ 
+   if (fread (string, read_length, 1, file) != 1)
+     return 1;
+ 
+   string[read_length] = 0;
+ 
+   if (fseek (file, tmp - read_length, SEEK_CUR) < 0)
+     return 1;
+ 
+   if (__read_long (&delim_from_file, file, 4) != 0)
+     return 1;
+ 
+   if (delim_from_file != delim)
+     return 1;
+ 
+   return 0;
+ }
+ 
  
  #endif /* ! GCC_GCOV_IO_H */
Index: gcov.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/gcov.c,v
retrieving revision 1.41
diff -c -3 -p -r1.41 gcov.c
*** gcov.c	5 Jan 2002 22:11:20 -0000	1.41
--- gcov.c	8 May 2002 10:10:33 -0000
*************** static void print_usage PARAMS ((int)) A
*** 232,237 ****
--- 232,238 ----
  static void print_version PARAMS ((void)) ATTRIBUTE_NORETURN;
  static void init_arc PARAMS ((struct adj_list *, int, int, struct bb_info *));
  static struct adj_list *reverse_arcs PARAMS ((struct adj_list *));
+ static gcov_type *read_profile PARAMS ((char *, long, int));
  static void create_program_flow_graph PARAMS ((struct bb_info_list *));
  static void solve_program_flow_graph PARAMS ((struct bb_info_list *));
  static void calculate_branch_probs PARAMS ((struct bb_info_list *, int,
*************** reverse_arcs (arcptr)
*** 538,543 ****
--- 539,668 ----
    return prev;
  }
  
+ /* 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);
+   rewind (da_file);
+   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;
+ 
+   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;
+ }
  
  /* Construct the program flow graph from the .bbg file, and read in the data
     in the .da file.  */
*************** create_program_flow_graph (bptr)
*** 550,555 ****
--- 675,703 ----
    int i;
    struct adj_list *arcptr;
    struct bb_info *bb_graph;
+   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);
+   
+   /* 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.  */
+   
+   /* Read the cfg checksum.  */
+   __read_long (&cfg_checksum, bbg_file, 4);
  
    /* Read the number of blocks.  */
    __read_long (&num_blocks, bbg_file, 4);
*************** create_program_flow_graph (bptr)
*** 579,585 ****
  	  init_arc (arcptr, src, dest, bb_graph);
  
  	  __read_long (&flag_bits, bbg_file, 4);
! 	  arcptr->on_tree = flag_bits & 0x1;
  	  arcptr->fake = !! (flag_bits & 0x2);
  	  arcptr->fall_through = !! (flag_bits & 0x4);
  	}
--- 727,736 ----
  	  init_arc (arcptr, src, dest, bb_graph);
  
  	  __read_long (&flag_bits, bbg_file, 4);
! 	  if (flag_bits & 0x1)
! 	    arcptr->on_tree++;
! 	  else 
! 	    instr_arcs++;
  	  arcptr->fake = !! (flag_bits & 0x2);
  	  arcptr->fall_through = !! (flag_bits & 0x4);
  	}
*************** create_program_flow_graph (bptr)
*** 601,606 ****
--- 752,761 ----
      if (bb_graph[i].succ)
        bb_graph[i].succ = reverse_arcs (bb_graph[i].succ);
  
+   /* Read profile from the .da file.  */
+ 
+   profile = read_profile (function_name, cfg_checksum, instr_arcs);
+ 
    /* For each arc not on the spanning tree, set its execution count from
       the .da file.  */
  
*************** create_program_flow_graph (bptr)
*** 613,627 ****
      for (arcptr = bb_graph[i].succ; arcptr; arcptr = arcptr->succ_next)
        if (! arcptr->on_tree)
  	{
! 	  gcov_type tmp_count = 0;
! 	  if (da_file && __read_gcov_type (&tmp_count, da_file, 8))
! 	    abort ();
! 
! 	  arcptr->arc_count = tmp_count;
  	  arcptr->count_valid = 1;
  	  bb_graph[i].succ_count--;
  	  bb_graph[arcptr->target].pred_count--;
  	}
  }
  
  static void
--- 768,780 ----
      for (arcptr = bb_graph[i].succ; arcptr; arcptr = arcptr->succ_next)
        if (! arcptr->on_tree)
  	{
! 	  arcptr->arc_count = profile[profile_pos++];
  	  arcptr->count_valid = 1;
  	  bb_graph[i].succ_count--;
  	  bb_graph[arcptr->target].pred_count--;
  	}
+   free (profile);
+   free (function_name);
  }
  
  static void
*************** read_files ()
*** 755,766 ****
    struct stat buf;
    struct bb_info_list *list_end = 0;
    struct bb_info_list *b_ptr;
-   long total;
- 
-   /* Read and ignore the first word of the .da file, which is the count of
-      how many numbers follow.  */
-   if (da_file && __read_long (&total, da_file, 8))
-     abort ();
  
    while (! feof (bbg_file))
      {
--- 908,913 ----
*************** read_files ()
*** 779,795 ****
  
        /* Set the EOF condition if at the end of file.  */
        ungetc (getc (bbg_file), bbg_file);
-     }
- 
-   /* Check to make sure the .da file data is valid.  */
- 
-   if (da_file)
-     {
-       if (feof (da_file))
- 	fnotice (stderr, ".da file contents exhausted too early\n");
-       /* Should be at end of file now.  */
-       if (__read_long (&total, da_file, 8) == 0)
- 	fnotice (stderr, ".da file contents not exhausted\n");
      }
  
    /* Calculate all of the basic block execution counts and branch
--- 926,931 ----
Index: libgcc2.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/libgcc2.c,v
retrieving revision 1.137
diff -c -3 -p -r1.137 libgcc2.c
*** libgcc2.c	3 Apr 2002 04:19:56 -0000	1.137
--- libgcc2.c	8 May 2002 10:10:34 -0000
*************** __eprintf (const char *string, const cha
*** 1238,1249 ****
  
  #ifdef L_bb
  
! #if LONG_TYPE_SIZE == GCOV_TYPE_SIZE
! typedef long gcov_type;
! #else
! typedef long long gcov_type;
! #endif
! 
  
  /* Structure emitted by -a  */
  struct bb
--- 1238,1248 ----
  
  #ifdef L_bb
  
! struct bb_function_info {
!   long checksum;
!   int arc_count;
!   const char *name;
! };
  
  /* Structure emitted by -a  */
  struct bb
*************** struct bb
*** 1253,1266 ****
    gcov_type *counts;
    long ncounts;
    struct bb *next;
-   const unsigned long *addresses;
  
    /* Older GCC's did not emit these fields.  */
    long nwords;
!   const char **functions;
!   const long *line_nums;
!   const char **filenames;
!   char *flags;
  };
  
  #ifdef BLOCK_PROFILER_CODE
--- 1252,1261 ----
    gcov_type *counts;
    long ncounts;
    struct bb *next;
  
    /* Older GCC's did not emit these fields.  */
    long nwords;
!   struct bb_function_info *function_infos;
  };
  
  #ifdef BLOCK_PROFILER_CODE
*************** BLOCK_PROFILER_CODE
*** 1283,1321 ****
  #include <errno.h>
  #endif
  
  static struct bb *bb_head;
  
  void
  __bb_exit_func (void)
  {
    FILE *da_file;
-   int i;
    struct bb *ptr;
  
    if (bb_head == 0)
      return;
  
!   i = strlen (bb_head->filename) - 3;
  
  
    for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
      {
!       int firstchar;
  
!       /* Make sure the output file exists -
!          but don't clobber exiting data.  */
!       if ((da_file = fopen (ptr->filename, "a")) != 0)
! 	fclose (da_file);
  
!       /* Need to re-open in order to be able to write from the start.  */
!       da_file = fopen (ptr->filename, "r+b");
        /* Some old systems might not allow the 'b' mode modifier.
           Therefore, try to open without it.  This can lead to a race
           condition so that when you delete and re-create the file, the
           file might be opened in text mode, but then, you shouldn't
           delete the file in the first place.  */
        if (da_file == 0)
! 	da_file = fopen (ptr->filename, "r+");
        if (da_file == 0)
  	{
  	  fprintf (stderr, "arc profiling: Can't open output file %s.\n",
--- 1278,1343 ----
  #include <errno.h>
  #endif
  
+ #include <gthr.h>
+ 
  static struct bb *bb_head;
  
+ int __global_counters = 0, __gthreads_active = 0;
+ 
  void
  __bb_exit_func (void)
  {
    FILE *da_file;
    struct bb *ptr;
+   long n_counters_p = 0;
+   gcov_type max_counter_p = 0;
+   gcov_type sum_counters_p = 0;
  
    if (bb_head == 0)
      return;
  
!   /* Calculate overall "statistics".  */
! 
!   for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
!     {
!       int i;
  
+       n_counters_p += ptr->ncounts;
+ 
+       for (i = 0; i < ptr->ncounts; i++)
+ 	{
+ 	  sum_counters_p += ptr->counts[i];
+ 
+ 	  if (ptr->counts[i] > max_counter_p)
+ 	    max_counter_p = ptr->counts[i];
+ 	}
+     }
  
    for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
      {
!       gcov_type max_counter_o = 0;
!       gcov_type sum_counters_o = 0;
!       int i;
  
!       /* Calculate the per-object statistics.  */
  
!       for (i = 0; i < ptr->ncounts; i++)
! 	{
! 	  sum_counters_o += ptr->counts[i];
! 
! 	  if (ptr->counts[i] > max_counter_o)
! 	    max_counter_o = ptr->counts[i];
! 	}
! 
!       /* open the file for appending, creating it if necessary.  */
!       da_file = fopen (ptr->filename, "ab");
        /* Some old systems might not allow the 'b' mode modifier.
           Therefore, try to open without it.  This can lead to a race
           condition so that when you delete and re-create the file, the
           file might be opened in text mode, but then, you shouldn't
           delete the file in the first place.  */
        if (da_file == 0)
! 	da_file = fopen (ptr->filename, "a");
        if (da_file == 0)
  	{
  	  fprintf (stderr, "arc profiling: Can't open output file %s.\n",
*************** __bb_exit_func (void)
*** 1341,1432 ****
        }
  #endif
  
!       /* If the file is not empty, and the number of counts in it is the
!          same, then merge them in.  */
!       firstchar = fgetc (da_file);
!       if (firstchar == EOF)
  	{
! 	  if (ferror (da_file))
! 	    {
! 	      fprintf (stderr, "arc profiling: Can't read output file ");
! 	      perror (ptr->filename);
! 	    }
  	}
        else
  	{
- 	  long n_counts = 0;
  
! 	  if (ungetc (firstchar, da_file) == EOF)
! 	    rewind (da_file);
! 	  if (__read_long (&n_counts, da_file, 8) != 0)
! 	    {
! 	      fprintf (stderr, "arc profiling: Can't read output file %s.\n",
! 		       ptr->filename);
! 	      continue;
! 	    }
  
! 	  if (n_counts == ptr->ncounts)
! 	    {
! 	      int i;
  
! 	      for (i = 0; i < n_counts; i++)
! 		{
! 		  gcov_type v = 0;
  
! 		  if (__read_gcov_type (&v, da_file, 8) != 0)
! 		    {
! 		      fprintf (stderr,
! 			       "arc profiling: Can't read output file %s.\n",
! 			       ptr->filename);
! 		      break;
! 		    }
! 		  ptr->counts[i] += v;
  		}
- 	    }
- 
- 	}
- 
-       rewind (da_file);
  
!       /* ??? Should first write a header to the file.  Preferably, a 4 byte
!          magic number, 4 bytes containing the time the program was
!          compiled, 4 bytes containing the last modification time of the
!          source file, and 4 bytes indicating the compiler options used.
  
!          That way we can easily verify that the proper source/executable/
!          data file combination is being used from gcov.  */
  
!       if (__write_gcov_type (ptr->ncounts, da_file, 8) != 0)
! 	{
  
! 	  fprintf (stderr, "arc profiling: Error writing output file %s.\n",
! 		   ptr->filename);
! 	}
!       else
! 	{
! 	  int j;
! 	  gcov_type *count_ptr = ptr->counts;
! 	  int ret = 0;
! 	  for (j = ptr->ncounts; j > 0; j--)
! 	    {
! 	      if (__write_gcov_type (*count_ptr, da_file, 8) != 0)
  		{
! 		  ret = 1;
  		  break;
  		}
- 	      count_ptr++;
  	    }
- 	  if (ret)
- 	    fprintf (stderr, "arc profiling: Error writing output file %s.\n",
- 		     ptr->filename);
  	}
  
!       if (fclose (da_file) == EOF)
  	fprintf (stderr, "arc profiling: Error closing output file %s.\n",
  		 ptr->filename);
      }
- 
-   return;
  }
  
  void
--- 1363,1458 ----
        }
  #endif
  
!       if (__write_long (-123, da_file, 4) != 0)	/* magic */
  	{
! 	  fprintf (stderr, "arc profiling: Error writing output file %s.\n",
! 		   ptr->filename);
  	}
        else
  	{
  
! 	  struct bb_function_info *fn_info;
! 	  gcov_type *count_ptr = ptr->counts;
! 	  int i;
! 	  int count_functions = 0;
  
! 	  for (fn_info = ptr->function_infos; fn_info->arc_count != -1;
! 	       fn_info++)
! 	    count_functions++;
! 
! 	  /* number of functions in this block.  */
! 	  __write_long (count_functions, da_file, 4);
! 
! 	  /* length of extra data in bytes.  */
! 	  __write_long ((4 + 8 + 8) + (4 + 8 + 8), da_file, 4);
! 
! 	  /* overall statistics. */
! 	  /* number of counters.  */
! 	  __write_long (n_counters_p, da_file, 4);	
! 	  /* sum of counters.  */
! 	  __write_gcov_type (sum_counters_p, da_file, 8);	
! 	  /* maximal counter.  */
! 	  __write_gcov_type (max_counter_p, da_file, 8);	
! 
! 	  /* per-object statistics. */
! 	  /* number of counters.  */
! 	  __write_long (ptr->ncounts, da_file, 4);	
! 	  /* sum of counters.  */
! 	  __write_gcov_type (sum_counters_o, da_file, 8);	
! 	  /* maximal counter.  */
! 	  __write_gcov_type (max_counter_o, da_file, 8);	
  
! 	  /* write execution counts for each function.  */
  
! 	  for (fn_info = ptr->function_infos; fn_info->arc_count != -1;
! 	       fn_info++)
! 	    {
! 	      /* new function.  */
! 	      if (__write_gcov_string
! 		  (fn_info->name, strlen (fn_info->name), da_file, -1) != 0)
! 		{
! 		  fprintf (stderr,
! 			   "arc profiling: Error writing output file %s.\n",
! 			   ptr->filename);
! 		  break;
  		}
  
! 	      if (__write_long (fn_info->checksum, da_file, 4) != 0)
! 		{
! 		  fprintf (stderr,
! 			   "arc profiling: Error writing output file %s.\n",
! 			   ptr->filename);
! 		  break;
! 		}
  
! 	      if (__write_long (fn_info->arc_count, da_file, 4) != 0)
! 		{
! 		  fprintf (stderr,
! 			   "arc profiling: Error writing output file %s.\n",
! 			   ptr->filename);
! 		  break;
! 		}
  
! 	      for (i = fn_info->arc_count; i > 0; i--, count_ptr++)
! 		{
! 		  if (__write_gcov_type (*count_ptr, da_file, 8) != 0)
! 		    break;
! 		}
  
! 	      if (i)		/* there was an error */
  		{
! 		  fprintf (stderr,
! 			   "arc profiling: Error writing output file %s.\n",
! 			   ptr->filename);
  		  break;
  		}
  	    }
  	}
  
!       if (fclose (da_file) != 0)
  	fprintf (stderr, "arc profiling: Error closing output file %s.\n",
  		 ptr->filename);
      }
  }
  
  void
*************** __bb_init_func (struct bb *blocks)
*** 1437,1444 ****
  
    if (blocks->zero_word)
      return;
! 
!   /* Initialize destructor.  */
    if (!bb_head)
      atexit (__bb_exit_func);
  
--- 1463,1470 ----
  
    if (blocks->zero_word)
      return;
!   
!   /* Initialize destructor and per-thread data.  */
    if (!bb_head)
      atexit (__bb_exit_func);
  
*************** __bb_init_func (struct bb *blocks)
*** 1451,1457 ****
  /* Called before fork or exec - write out profile information gathered so
     far and reset it to zero.  This avoids duplication or loss of the
     profile information gathered so far.  */
! void
  __bb_fork_func (void)
  {
    struct bb *ptr;
--- 1477,1483 ----
  /* Called before fork or exec - write out profile information gathered so
     far and reset it to zero.  This avoids duplication or loss of the
     profile information gathered so far.  */
! void 
  __bb_fork_func (void)
  {
    struct bb *ptr;
Index: libgcc2.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/libgcc2.h,v
retrieving revision 1.20
diff -c -3 -p -r1.20 libgcc2.h
*** libgcc2.h	22 Aug 2001 14:35:22 -0000	1.20
--- libgcc2.h	8 May 2002 10:10:34 -0000
*************** struct bb;
*** 31,39 ****
  extern void __bb_exit_func (void);
  extern void __bb_init_func (struct bb *);
  extern void __bb_fork_func (void);
! extern void __bb_trace_func (void);
! extern void __bb_trace_ret (void);
! extern void __bb_init_trace_func (struct bb *, unsigned long);
  
  struct exception_descriptor;
  extern short int __get_eh_table_language (struct exception_descriptor *);
--- 31,44 ----
  extern void __bb_exit_func (void);
  extern void __bb_init_func (struct bb *);
  extern void __bb_fork_func (void);
! 
! #if LONG_TYPE_SIZE == GCOV_TYPE_SIZE
! typedef long gcov_type;
! #else
! typedef long long gcov_type;
! #endif
! 
! extern gcov_type *__bb_find_arc_counters (void);
  
  struct exception_descriptor;
  extern short int __get_eh_table_language (struct exception_descriptor *);
Index: profile.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/profile.c,v
retrieving revision 1.82
diff -c -3 -p -r1.82 profile.c
*** profile.c	21 Mar 2002 18:39:13 -0000	1.82
--- profile.c	8 May 2002 10:10:37 -0000
*************** Software Foundation, 59 Temple Place - S
*** 49,54 ****
--- 49,56 ----
  #include "basic-block.h"
  #include "gcov-io.h"
  #include "target.h"
+ #include "profile.h"
+ #include "libfuncs.h"
  #include "langhooks.h"
  
  /* Additional information about the edges we need.  */
*************** static FILE *bb_file;
*** 92,102 ****
  
  static char *last_bb_file_name;
  
- /* Used by final, for allocating the proper amount of storage for the
-    instrumented arc execution counts.  */
- 
- int count_instrumented_edges;
- 
  /* Collect statistics on the performance of this pass for the entire source
     file.  */
  
--- 94,99 ----
*************** static rtx gen_edge_profiler PARAMS ((in
*** 118,123 ****
--- 115,122 ----
  static void instrument_edges PARAMS ((struct edge_list *));
  static void output_gcov_string PARAMS ((const char *, long));
  static void compute_branch_probabilities PARAMS ((void));
+ static gcov_type * get_exec_counts PARAMS ((void));
+ static long compute_checksum PARAMS ((void));
  static basic_block find_group PARAMS ((basic_block));
  static void union_groups PARAMS ((basic_block, basic_block));
  
*************** instrument_edges (el)
*** 163,170 ****
  	}
      }
  
    total_num_edges_instrumented += num_instr_edges;
!   count_instrumented_edges = total_num_edges_instrumented;
  
    total_num_blocks_created += num_edges;
    if (rtl_dump_file)
--- 162,170 ----
  	}
      }
  
+   profile_info.count_edges_instrumented_now = num_instr_edges;
    total_num_edges_instrumented += num_instr_edges;
!   profile_info.count_instrumented_edges = total_num_edges_instrumented;
  
    total_num_blocks_created += num_edges;
    if (rtl_dump_file)
*************** output_gcov_string (string, delimiter)
*** 205,210 ****
--- 205,371 ----
  }
  
  
+ /* Computes hybrid profile for all matching entries in da_file. 
+    Sets max_counter_in_program as a side effect.  */
+ 
+ static gcov_type *
+ get_exec_counts ()
+ {
+   int num_edges = 0;
+   int i;
+   int okay = 1;
+   int mismatch = 0;
+   gcov_type *profile;
+   char *function_name_buffer;
+   int function_name_buffer_len;
+   gcov_type max_counter_in_run;
+ 
+   profile_info.max_counter_in_program = 0;
+   profile_info.count_profiles_merged = 0;
+ 
+   /* No .da file, no execution counts.  */
+   if (!da_file)
+     return 0;
+ 
+   /* Count the edges to be (possibly) instrumented.  */
+ 
+   for (i = 0; i < n_basic_blocks + 2; i++)
+     {
+       basic_block bb = GCOV_INDEX_TO_BB (i);
+       edge e;
+       for (e = bb->succ; e; e = e->succ_next)
+ 	if (!EDGE_INFO (e)->ignore && !EDGE_INFO (e)->on_tree)
+ 	  {
+ 	    num_edges++;
+ 	  }
+     }
+ 
+   /* now read and combine all matching profiles. */
+ 
+   profile = xmalloc (sizeof (gcov_type) * num_edges);
+   rewind (da_file);
+   function_name_buffer_len = strlen (current_function_name) + 1;
+   function_name_buffer = xmalloc (function_name_buffer_len + 1);
+ 
+   for (i = 0; i < num_edges; i++)
+     profile[i] = 0;
+ 
+   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;
+ 	}
+ 
+       fseek (da_file, 4 + 8, SEEK_CUR);
+ 
+       /* read the maximal counter.  */
+       __read_gcov_type (&max_counter_in_run, da_file, 8);
+ 
+       /* skip the rest of "statistics" emited by __bb_exit_func.  */
+       fseek (da_file, extra_bytes - (4 + 8 + 8), 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, current_function_name) != 0)
+ 	    {
+ 	      /* skip */
+ 	      if (fseek (da_file, arc_count * 8, SEEK_CUR) < 0)
+ 		{
+ 		  okay = 0;
+ 		  break;
+ 		}
+ 	    }
+ 	  else if (arc_count != num_edges
+ 		   || chksum != profile_info.current_function_cfg_checksum)
+ 	    okay = 0, mismatch = 1;
+ 	  else
+ 	    {
+ 	      gcov_type tmp;
+ 
+ 	      profile_info.max_counter_in_program += max_counter_in_run;
+ 	      profile_info.count_profiles_merged++;
+ 
+ 	      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)
+     {
+       if (mismatch)
+ 	error
+ 	  ("Profile does not match flowgraph of function %s (out of date?)",
+ 	   current_function_name);
+       else
+ 	error (".da file corrupted");
+       free (profile);
+       return 0;
+     }
+ 
+   return profile;
+ }
+ 
+ 
  /* Compute the branch probabilities for the various branches.
     Annotate them accordingly.  */
  
*************** compute_branch_probabilities ()
*** 218,223 ****
--- 379,386 ----
    int hist_br_prob[20];
    int num_never_executed;
    int num_branches;
+   gcov_type *exec_counts = get_exec_counts ();
+   int exec_counts_pos = 0;
  
    /* Attach extra info block to each bb.  */
  
*************** compute_branch_probabilities ()
*** 253,266 ****
  	if (!EDGE_INFO (e)->ignore && !EDGE_INFO (e)->on_tree)
  	  {
  	    num_edges++;
! 	    if (da_file)
  	      {
! 		gcov_type value;
! 		__read_gcov_type (&value, da_file, 8);
! 		e->count = value;
  	      }
  	    else
  	      e->count = 0;
  	    EDGE_INFO (e)->count_valid = 1;
  	    BB_INFO (bb)->succ_count--;
  	    BB_INFO (e->dest)->pred_count--;
--- 416,428 ----
  	if (!EDGE_INFO (e)->ignore && !EDGE_INFO (e)->on_tree)
  	  {
  	    num_edges++;
! 	    if (exec_counts)
  	      {
! 		e->count = exec_counts[exec_counts_pos++];
  	      }
  	    else
  	      e->count = 0;
+ 
  	    EDGE_INFO (e)->count_valid = 1;
  	    BB_INFO (bb)->succ_count--;
  	    BB_INFO (e->dest)->pred_count--;
*************** compute_branch_probabilities ()
*** 517,522 ****
--- 679,714 ----
      }
  
    free_aux_for_blocks ();
+   if (exec_counts)
+     free (exec_counts);
+ }
+ 
+ /* Compute checksum for the current function.  */
+ 
+ #define CHSUM_HASH	500000003
+ #define CHSUM_SHIFT	2
+ 
+ static long
+ compute_checksum ()
+ {
+   long chsum = 0;
+   int i;
+ 
+   
+   for (i = 0; i < n_basic_blocks ; i++)
+     {
+       basic_block bb = BASIC_BLOCK (i);
+       edge e;
+ 
+       for (e = bb->succ; e; e = e->succ_next)
+ 	{
+ 	  chsum = ((chsum << CHSUM_SHIFT) + (BB_TO_GCOV_INDEX (e->dest) + 1)) % CHSUM_HASH;
+ 	}
+ 
+       chsum = (chsum << CHSUM_SHIFT) % CHSUM_HASH;
+     }
+ 
+   return chsum;
  }
  
  /* Instrument and/or analyze program behavior based on program flow graph.
*************** branch_prob ()
*** 542,547 ****
--- 734,745 ----
    int num_edges, ignored_edges;
    struct edge_list *el;
  
+   profile_info.current_function_cfg_checksum = compute_checksum ();
+ 
+   if (rtl_dump_file)
+     fprintf (rtl_dump_file, "CFG checksum is %ld\n", 
+ 	profile_info.current_function_cfg_checksum);
+   
    /* Start of a function.  */
    if (flag_test_coverage)
      output_gcov_string (current_function_name, (long) -2);
*************** branch_prob ()
*** 758,763 ****
--- 956,967 ----
      {
        int flag_bits;
  
+       __write_gcov_string (current_function_name,
+ 		           strlen (current_function_name), bbg_file, -1);
+ 
+       /* write checksum.  */
+       __write_long (profile_info.current_function_cfg_checksum, bbg_file, 4);
+       
        /* The plus 2 stands for entry and exit block.  */
        __write_long (n_basic_blocks + 2, bbg_file, 4);
        __write_long (num_edges - ignored_edges + 1, bbg_file, 4);
*************** find_spanning_tree (el)
*** 884,897 ****
    /* Add fake edge exit to entry we can't instrument.  */
    union_groups (EXIT_BLOCK_PTR, ENTRY_BLOCK_PTR);
  
!   /* First add all abnormal edges to the tree unless they form an cycle.  */
    for (i = 0; i < num_edges; i++)
      {
        edge e = INDEX_EDGE (el, i);
!       if ((e->flags & (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL | EDGE_FAKE))
  	  && !EDGE_INFO (e)->ignore
  	  && (find_group (e->src) != find_group (e->dest)))
  	{
  	  EDGE_INFO (e)->on_tree = 1;
  	  union_groups (e->src, e->dest);
  	}
--- 1088,1108 ----
    /* Add fake edge exit to entry we can't instrument.  */
    union_groups (EXIT_BLOCK_PTR, ENTRY_BLOCK_PTR);
  
!   /* First add all abnormal edges to the tree unless they form an cycle. Also
!      add all edges to EXIT_BLOCK_PTR to avoid inserting profiling code behind
!      setting return value from function.  */
    for (i = 0; i < num_edges; i++)
      {
        edge e = INDEX_EDGE (el, i);
!       if (((e->flags & (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL | EDGE_FAKE))
!            || e->dest == EXIT_BLOCK_PTR
!           )
  	  && !EDGE_INFO (e)->ignore
  	  && (find_group (e->src) != find_group (e->dest)))
  	{
+ 	  if (rtl_dump_file)
+ 	    fprintf (rtl_dump_file, "Abnormal edge %d to %d put to tree\n",
+                      e->src->index, e->dest->index);
  	  EDGE_INFO (e)->on_tree = 1;
  	  union_groups (e->src, e->dest);
  	}
*************** find_spanning_tree (el)
*** 905,910 ****
--- 1116,1124 ----
  	  && !EDGE_INFO (e)->ignore
  	  && (find_group (e->src) != find_group (e->dest)))
  	{
+ 	  if (rtl_dump_file)
+ 	    fprintf (rtl_dump_file, "Critical edge %d to %d put to tree\n",
+                      e->src->index, e->dest->index);
  	  EDGE_INFO (e)->on_tree = 1;
  	  union_groups (e->src, e->dest);
  	}
*************** find_spanning_tree (el)
*** 917,922 ****
--- 1131,1139 ----
        if (find_group (e->src) != find_group (e->dest)
  	  && !EDGE_INFO (e)->ignore)
  	{
+ 	  if (rtl_dump_file)
+ 	    fprintf (rtl_dump_file, "Normal edge %d to %d put to tree\n",
+                      e->src->index, e->dest->index);
  	  EDGE_INFO (e)->on_tree = 1;
  	  union_groups (e->src, e->dest);
  	}
*************** init_branch_prob (filename)
*** 975,986 ****
        if ((da_file = fopen (da_file_name, "rb")) == 0)
  	warning ("file %s not found, execution counts assumed to be zero",
  		 da_file_name);
- 
-       /* The first word in the .da file gives the number of instrumented
- 	 edges, which is not needed for our purposes.  */
- 
-       if (da_file)
- 	__read_long (&len, da_file, 8);
      }
  
    if (profile_arc_flag)
--- 1192,1197 ----
*************** end_branch_prob ()
*** 1011,1032 ****
        fclose (bbg_file);
      }
  
!   if (flag_branch_probabilities)
!     {
!       if (da_file)
! 	{
! 	  long temp;
! 	  /* This seems slightly dangerous, as it presumes the EOF
! 	     flag will not be set until an attempt is made to read
! 	     past the end of the file.  */
! 	  if (feof (da_file))
! 	    error (".da file contents exhausted too early");
! 	  /* Should be at end of file now.  */
! 	  if (__read_long (&temp, da_file, 8) == 0)
! 	    error (".da file contents not exhausted");
! 	  fclose (da_file);
! 	}
!     }
  
    if (rtl_dump_file)
      {
--- 1222,1229 ----
        fclose (bbg_file);
      }
  
!   if (flag_branch_probabilities && da_file)
!     fclose (da_file);
  
    if (rtl_dump_file)
      {
*************** gen_edge_profiler (edgeno)
*** 1097,1102 ****
--- 1294,1301 ----
    tmp = expand_simple_binop (mode, PLUS, mem_ref, const1_rtx,
  			     mem_ref, 0, OPTAB_WIDEN);
  
+   set_mem_alias_set (mem_ref, new_alias_set ());
+ 
    if (tmp != mem_ref)
      emit_move_insn (copy_rtx (mem_ref), tmp);
  
*************** output_func_start_profiler ()
*** 1118,1126 ****
    rtx table_address;
    enum machine_mode mode = mode_for_size (GCOV_TYPE_SIZE, MODE_INT, 0);
    int save_flag_inline_functions = flag_inline_functions;
-   int save_flag_test_coverage = flag_test_coverage;
-   int save_profile_arc_flag = profile_arc_flag;
-   int save_flag_branch_probabilities = flag_branch_probabilities;
  
    /* It's either already been output, or we don't need it because we're
       not doing profile-edges.  */
--- 1317,1322 ----
*************** output_func_start_profiler ()
*** 1163,1168 ****
--- 1359,1365 ----
    init_function_start (fndecl, input_filename, lineno);
    (*lang_hooks.decls.pushlevel) (0);
    expand_function_start (fndecl, 0);
+   cfun->arc_profile = 0;
  
    /* Actually generate the code to call __bb_init_func.  */
    ASM_GENERATE_INTERNAL_LABEL (buf, "LPBX", 0);
*************** output_func_start_profiler ()
*** 1179,1198 ****
       flag_inline_functions.  */
    flag_inline_functions = 0;
  
-   /* Don't instrument the function that turns on instrumentation.  Which
-      is also handy since we'd get silly warnings about not consuming all
-      of our da_file input.  */
-   flag_test_coverage = 0;
-   profile_arc_flag = 0;
-   flag_branch_probabilities = 0;
- 
    rest_of_compilation (fndecl);
  
    /* Reset flag_inline_functions to its original value.  */
    flag_inline_functions = save_flag_inline_functions;
-   flag_test_coverage = save_flag_test_coverage;
-   profile_arc_flag = save_profile_arc_flag;
-   flag_branch_probabilities = save_flag_branch_probabilities;
  
    if (! quiet_flag)
      fflush (asm_out_file);
--- 1376,1385 ----
Index: toplev.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/toplev.c,v
retrieving revision 1.621
diff -c -3 -p -r1.621 toplev.c
*** toplev.c	8 May 2002 09:17:27 -0000	1.621
--- toplev.c	8 May 2002 10:10:39 -0000
*************** int profile_flag = 0;
*** 364,369 ****
--- 364,374 ----
  
  int profile_arc_flag = 0;
  
+ /* Nonzero if we should not attempt to generate thread-safe
+    code to profile program flow graph arcs.  */
+ 
+ int flag_unsafe_profile_arcs = 0;
+ 
  /* Nonzero if generating info for gcov to calculate line test coverage.  */
  
  int flag_test_coverage = 0;
*************** static const lang_independent_options f_
*** 1061,1066 ****
--- 1066,1073 ----
     N_("Support synchronous non-call exceptions") },
    {"profile-arcs", &profile_arc_flag, 1,
     N_("Insert arc based program profiling code") },
+   {"unsafe-profile-arcs", &flag_unsafe_profile_arcs, 1,
+    N_("Avoid thread safety profiling overhead") },
    {"test-coverage", &flag_test_coverage, 1,
     N_("Create data files needed by gcov") },
    {"branch-probabilities", &flag_branch_probabilities, 1,
*************** rest_of_compilation (decl)
*** 2891,2904 ****
    close_dump_file (DFI_cfg, print_rtl_with_bb, insns);
  
    /* Do branch profiling and static profile estimation passes.  */
!   if (optimize > 0 || profile_arc_flag || flag_test_coverage
!       || flag_branch_probabilities)
      {
        struct loops loops;
  
        timevar_push (TV_BRANCH_PROB);
        open_dump_file (DFI_bp, decl);
!       if (profile_arc_flag || flag_test_coverage || flag_branch_probabilities)
  	branch_prob ();
  
        /* Discover and record the loop depth at the head of each basic
--- 2898,2910 ----
    close_dump_file (DFI_cfg, print_rtl_with_bb, insns);
  
    /* Do branch profiling and static profile estimation passes.  */
!   if (optimize > 0 || cfun->arc_profile || flag_branch_probabilities)
      {
        struct loops loops;
  
        timevar_push (TV_BRANCH_PROB);
        open_dump_file (DFI_bp, decl);
!       if (cfun->arc_profile || flag_branch_probabilities)
  	branch_prob ();
  
        /* Discover and record the loop depth at the head of each basic
Index: doc/gcov.texi
===================================================================
RCS file: /cvs/gcc/egcs/gcc/doc/gcov.texi,v
retrieving revision 1.7
diff -c -3 -p -r1.7 gcov.texi
*** doc/gcov.texi	14 Nov 2001 00:47:40 -0000	1.7
--- doc/gcov.texi	8 May 2002 10:10:41 -0000
*************** program flow.
*** 363,368 ****
--- 363,370 ----
  
  In the @file{.bbg} file, the format is:
  @smallexample
+         name of function #0
+         checksum of function #0
          number of basic blocks for function #0 (4-byte number)
          total number of arcs for function #0 (4-byte number)
          count of arcs in basic block #0 (4-byte number)
*************** A @minus{}1 (stored as a 4-byte number) 
*** 383,388 ****
--- 385,393 ----
  list of basic blocks, and to verify that the file has been read
  correctly.
  
+ The function name is stored as a @minus{}1 (4 bytes), the length (4 bytes),
+ the name itself (padded to 4-byte boundary) followed by a @minus{}1 (4 bytes).
+ 
  The @file{.da} file is generated when a program containing object files
  built with the GCC @option{-fprofile-arcs} option is executed.  A
  separate @file{.da} file is created for each source file compiled with
*************** this option, and the name of the @file{.
*** 390,404 ****
  absolute pathname in the resulting object file.  This path name is
  derived from the source file name by substituting a @file{.da} suffix.
  
! The format of the @file{.da} file is fairly simple.  The first 8-byte
! number is the number of counts in the file, followed by the counts
! (stored as 8-byte numbers).  Each count corresponds to the number of
! times each arc in the program is executed.  The counts are cumulative;
! each time the program is executed, it attempts to combine the existing
! @file{.da} files with the new counts for this invocation of the
! program.  It ignores the contents of any @file{.da} files whose number of
! arcs doesn't correspond to the current program, and merely overwrites
! them instead.
  
  All three of these files use the functions in @file{gcov-io.h} to store
  integers; the functions in this header provide a machine-independent
--- 395,426 ----
  absolute pathname in the resulting object file.  This path name is
  derived from the source file name by substituting a @file{.da} suffix.
  
! The @file{.da} consists of several blocks (one for each run) with the following structure:
! @smallexample
!         "magic" number @minus{}123 (4-byte number)
! 	number of functions (4-byte number)
!         length of the "extension block" in bytes
! 	extension block (variable length)
!   	name of function #0 (the same format as in .bbg file)
!         checksum of function #0
! 	number of instrumented arcs (4-byte number)
!         count of arc #0 (8-byte number)
!         count of arc #1 (8-byte number)
!         @dots{}
! 	count of arc #M_0 (8-byte number)
!   	name of function #1 (the same format as in .bbg file)
!         checksum of function #1
! 	@dots{}
! @end smallexample
! The current structure of the extension block is as follows:
! @smallexample
!         number of instrumented arcs in whole program (4-byte number)
!         sum all of instrumented arcs in whole program (8-byte number)
!         maximal value of counter in whole program (8-byte number)
!         number of instrumented arcs in the object file (4-byte number)
!         sum all of instrumented arcs in the object file (8-byte number)
!         maximal value of counter in the object file (8-byte number)
! @end smallexample
  
  All three of these files use the functions in @file{gcov-io.h} to store
  integers; the functions in this header provide a machine-independent


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]