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]

Mainline merge part 14 - profiler improvements


Hi,
this patch shamelessly combines three changes to arc profiler from cfg-branch
patch.  There is some interference, so it idificult to split the patches,
but in case some parts turns out to be problematic, I will do so.

The first change (done by Pavel) is to use trees to output the datastructures,
so we don't run into layout problem.

Second change (also by Pavel) is the change of file format.  It is now little
bit extensible and allows storing of multiple profiles (so they can be better
analyzed later).  It also contains overall statistics I use in other code.
There is also checksum, so we no longer run out of sync in the tables and
produce messy code.

Last change (by Zdenek) is to add thread safety to the profiling.  Now the
data are per-thread so conflict does not happen and are merged at thread
exit.  Also function is called at each entry point to get the thread
specific pointer.

Lots of the cfg-branch code relies on the statistics part of Pavel's patch
so I would like to get this resolved soon :)

Honza

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

	Tue Apr 23 18:31:36 CEST 2002  Pavel Nejedly

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

	Thu Nov 22 02:24:39 CET 2001  Zdenek Dvorak

	* Makefile.in (profile.o): Add dependency on libfuncs.h and gthr.h.
	(XCFLAGS): Add GTHREAD_FLAGS.
	* function.h (struct function): Add arc_counters_adress and no_profile.
	* final.c (end_final): Emit LPBF label.
	* flags.h (flag_unsafe_profile_arcs): New.
	* libfuncs.h (enum libfunc_index): Add LTI_find_arc_counters.
	* libgcc2.c: Include gthr.h.
	(__bb_find_arc_counters, __bb_thread_start_func, __bb_thread_end_func):
	New.
	(__bb_exit_func, __bb_init_func, __bb_find_arc_counters,
	__bb_thread_start_func, __bb_thread_end_func): Handle thread-safe
	profiling.
	* libgcc2.h (__bb_init_func): Modified declaration.
	(__bb_thread_start_func, __bb_thread_end_func, __bb_find_arc_counters):
	Declared.
	* optabs.c (init_optabs): Init __bb_find_arc_counters.
	* profile.c: Include libfuncs.h and gthr.h.
	(insert_profiler_initialization): New static function.
	(instrument_edges): Modified.
	(branch_prob): Handle no_profile, insert per-function profiler code.
	(find_spanning_tree): More information to dump.
	(gen_edge_profiler): Generate thread-safe profiling code.
	(output_func_start_profiler): Modified.
	* toplev.c (flag_unsafe_profile_arcs): New.
	(f_options): New flag "unsafe-profile-arcs".

	Tue Jan  1 21:12:40 CET 2002  Pavel Nejedly

	* 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.866
diff -c -3 -p -r1.866 Makefile.in
*** Makefile.in	4 May 2002 20:14:57 -0000	1.866
--- Makefile.in	6 May 2002 13:42:10 -0000
*************** varasm.o : varasm.c $(CONFIG_H) $(SYSTEM
*** 1385,1391 ****
  function.o : function.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h \
     function.h $(EXPR_H) libfuncs.h $(REGS_H) hard-reg-set.h \
     insn-config.h $(RECOG_H) output.h toplev.h except.h hash.h $(GGC_H) \
!    $(TM_P_H) langhooks.h
  stmt.o : stmt.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h function.h  \
     insn-config.h hard-reg-set.h $(EXPR_H) libfuncs.h except.h \
     $(LOOP_H) $(RECOG_H) toplev.h output.h varray.h $(GGC_H) $(TM_P_H) \
--- 1385,1391 ----
  function.o : function.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h \
     function.h $(EXPR_H) libfuncs.h $(REGS_H) hard-reg-set.h \
     insn-config.h $(RECOG_H) output.h toplev.h except.h hash.h $(GGC_H) \
!    $(TM_P_H) langhooks.h gthr.h
  stmt.o : stmt.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h function.h  \
     insn-config.h hard-reg-set.h $(EXPR_H) libfuncs.h except.h \
     $(LOOP_H) $(RECOG_H) toplev.h output.h varray.h $(GGC_H) $(TM_P_H) \
*************** 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 gthr.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	6 May 2002 13:42:12 -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,372 ****
    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,513 ----
    if (profile_arc_flag)
      {
        char name[20];
!       tree char_pointer_type, char_array_type, string_type, string_cst;
!       tree structure_decl, structure_value, structure_pointer_type;
!       tree field_decl, field_value, decl_chain, value_chain;
!       tree nwords_field_value;
! 
!       /* Build types.  */
!       char_pointer_type = build_pointer_type (char_type_node);
!       char_array_type = build_array_type (char_type_node, integer_type_node);
!       string_type = build_pointer_type (char_array_type);
! 
!       /* 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 = make_node (TREE_LIST);
!       TREE_TYPE (value_chain) = long_integer_type_node;
!       TREE_PURPOSE (value_chain) = decl_chain;
!       TREE_VALUE (value_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"), char_pointer_type);
! 	  field_value = make_node (TREE_LIST);
! 	  TREE_TYPE (field_value) = char_pointer_type;
! 	  TREE_PURPOSE (field_value) = field_decl;
! 	  string_cst = build_string (strlen (da_filename) + 1, da_filename);
! 	  TREE_TYPE (string_cst) = char_array_type;
! 	  TREE_VALUE (field_value) = build1 (ADDR_EXPR, string_type, string_cst);
! 	  chainon (value_chain, field_value);
! 	  chainon (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 = make_node (INTEGER_TYPE);
! 	  tree counts_table;
! 
! 	  TYPE_MIN_VALUE (domain_tree) = integer_zero_node;
! 	  TYPE_MAX_VALUE (domain_tree) = build_int_2 (profile_info.count_instrumented_edges - 1, 0);
! 	  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);
! 	  field_value = make_node (TREE_LIST);
! 	  TREE_TYPE (field_value) = gcov_type_pointer_type;
! 	  TREE_PURPOSE (field_value) = field_decl;
! 	  TREE_VALUE (field_value) = build1 (ADDR_EXPR, gcov_type_array_pointer_type, counts_table);
! 	  chainon (value_chain, field_value);
! 	  chainon (decl_chain, field_decl);
! 	}
  
        /* Count of the # of instrumented arcs.  */
!       field_decl = build_decl (FIELD_DECL, get_identifier ("ncounts"), long_integer_type_node);
!       field_value = make_node (TREE_LIST);
!       TREE_TYPE (field_value) = long_integer_type_node;
!       TREE_PURPOSE (field_value) = field_decl;
!       TREE_VALUE (field_value) = build_int_2 (profile_info.count_instrumented_edges, 0);
!       chainon (value_chain, field_value);
!       chainon (decl_chain, field_decl);
! 
!       /* Pointer to the next bb.  */
!       field_decl = build_decl (FIELD_DECL, get_identifier ("next"), structure_pointer_type);
!       field_value = make_node (TREE_LIST);
!       TREE_TYPE (field_value) = structure_pointer_type;
!       TREE_PURPOSE (field_value) = field_decl;
!       TREE_VALUE (field_value) = integer_zero_node;
!       chainon (value_chain, field_value);
!       chainon (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);
!       nwords_field_value = field_value = make_node (TREE_LIST);
!       TREE_TYPE (field_value) = long_integer_type_node;
!       TREE_PURPOSE (field_value) = field_decl;
!       chainon (value_chain, field_value);
!       chainon (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;
! 	tree array_field;
! 
! 	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);
! 	name_field = build_decl (FIELD_DECL, get_identifier ("name"),
! 				 char_pointer_type);
! 	chainon (checksum_field, arc_count_field);
! 	chainon (checksum_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 = make_node (TREE_LIST);
! 	    TREE_TYPE (field_value_chain) = long_integer_type_node;
! 	    TREE_PURPOSE (field_value_chain) = checksum_field;
! 	    TREE_VALUE (field_value_chain) = build_int_2 (item->cfg_checksum,
! 							  0);
! 	    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 (item->count_edges, 0);
! 	    chainon (field_value_chain, field_value);
! 
! 	    field_value = make_node (TREE_LIST);
! 	    TREE_TYPE (field_value) = string_type;
! 	    TREE_PURPOSE (field_value) = name_field;
! 	    string_cst = build_string (strlen (item->name) + 1, item->name);
! 	    TREE_TYPE (string_cst) = char_array_type;
! 	    TREE_VALUE (field_value) = build1 (ADDR_EXPR, string_type, string_cst);
! 	    chainon (field_value_chain, field_value);
! 
! 	    array_field = make_node (TREE_LIST);
! 	    TREE_TYPE (array_field) = bb_fn_struct_type;
! 	    TREE_VALUE (array_field) = build (CONSTRUCTOR, bb_fn_struct_type,
! 					      NULL_TREE, field_value_chain);
! 	    /* Add to chain.  */
! 
! 	    if (array_value_chain == NULL_TREE)
! 	      array_value_chain = array_field;
! 	    else
! 	      chainon (array_value_chain, array_field);
! 	  }
  
! 	/* 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_field = make_node (TREE_LIST);
! 	TREE_TYPE (array_field) = bb_fn_struct_type;
! 	TREE_VALUE (array_field) = build (CONSTRUCTOR, bb_fn_struct_type,
! 					  NULL_TREE, field_value);
  
! 	if (array_value_chain == NULL_TREE)
! 	  array_value_chain = array_field;
! 	else
! 	  chainon (array_value_chain, array_field);
  
! 	/* Create constructor for array.  */
! 	
! 	field_decl = build_decl (FIELD_DECL, get_identifier ("function_infos"),
! 				 bb_fn_struct_pointer_type);
! 	field_value = make_node (TREE_LIST);
! 	TREE_TYPE (field_value) = bb_fn_struct_pointer_type;
! 	TREE_PURPOSE (field_value) = field_decl;
! 	TREE_VALUE (field_value) = build1 (ADDR_EXPR,
! 					   bb_fn_struct_array_pointer_type,
! 					   build (CONSTRUCTOR,
! 						  bb_fn_struct_array_type,
! 						  NULL_TREE,
! 						  array_value_chain));
! 	chainon (value_chain, field_value);
! 	chainon (decl_chain, field_decl);
!       }
  
  
!       /* Finish structure.  */
!       TYPE_FIELDS (structure_decl) = 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, 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 ****
--- 1922,1945 ----
        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: flags.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/flags.h,v
retrieving revision 1.83
diff -c -3 -p -r1.83 flags.h
*** flags.h	26 Mar 2002 15:36:34 -0000	1.83
--- flags.h	6 May 2002 13:42:13 -0000
*************** extern int profile_flag;
*** 192,197 ****
--- 192,202 ----
  
  extern int profile_arc_flag;
  
+ /* Nonzero if we should not attempt to generate thread-safe
+    code to profile program flow graph arcs.  */
+ 
+ extern int flag_unsafe_profile_arcs;
+ 
  /* Nonzero if generating info for gcov to calculate line test coverage.  */
  
  extern int flag_test_coverage;
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	6 May 2002 13:42:35 -0000
*************** Software Foundation, 59 Temple Place - S
*** 59,64 ****
--- 59,65 ----
  #include "ggc.h"
  #include "tm_p.h"
  #include "integrate.h"
+ #include "gthr.h"
  #include "langhooks.h"
  
  #ifndef TRAMPOLINE_ALIGNMENT
*************** expand_main_function ()
*** 6458,6463 ****
--- 6459,6478 ----
    emit_library_call (gen_rtx_SYMBOL_REF (Pmode, NAME__MAIN), LCT_NORMAL,
  		     VOIDmode, 0);
  #endif
+ 
+ #ifdef __GTHREADS
+   if (profile_arc_flag && !flag_unsafe_profile_arcs)
+     {
+       rtx globc =
+         gen_rtx_MEM (SImode,
+                      gen_rtx_SYMBOL_REF (Pmode, "__global_counters"));
+       rtx gthr_act =
+         gen_rtx_MEM (SImode,
+                      gen_rtx_SYMBOL_REF (Pmode, "__gthreads_active"));
+ 
+       emit_move_insn (globc, gthr_act);
+     }
+ #endif
  }
  
  extern struct obstack permanent_obstack;
*************** expand_function_start (subr, parms_have_
*** 6505,6510 ****
--- 6520,6529 ----
    current_function_instrument_entry_exit
      = (flag_instrument_function_entry_exit
         && ! DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (subr));
+ 
+   cfun->no_profile
+     = (lookup_attribute ("no_profile", DECL_ATTRIBUTES (current_function_decl))
+        != NULL);
  
    current_function_profile
      = (profile_flag
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	6 May 2002 13:42:37 -0000
*************** struct function
*** 385,390 ****
--- 385,393 ----
       delay list for them is recorded here.  */
    rtx epilogue_delay_list;
  
+   /* Where is adress of arc counters placed to?  */
+   rtx arc_counters_adress;
+ 
    /* Collected bit flags.  */
  
    /* Nonzero if function being compiled needs to be given an address
*************** struct function
*** 436,441 ****
--- 439,447 ----
    /* Nonzero if instrumentation calls for function entry and exit should be
       generated.  */
    unsigned int instrument_entry_exit : 1;
+ 
+   /* Nonzero if no profiling should be done for the function.  */
+   unsigned int no_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	6 May 2002 13:42:38 -0000
*************** static int __fetch_gcov_type PARAMS ((gc
*** 31,36 ****
--- 31,38 ----
  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 ****
--- 194,287 ----
    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	6 May 2002 13:42:40 -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,664 ----
    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 ****
--- 671,699 ----
    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);
  	}
--- 723,732 ----
  	  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 ****
--- 748,757 ----
      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
--- 764,776 ----
      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))
      {
--- 904,909 ----
*************** 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
--- 922,927 ----
Index: libfuncs.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/libfuncs.h,v
retrieving revision 1.4
diff -c -3 -p -r1.4 libfuncs.h
*** libfuncs.h	31 Mar 2002 09:52:34 -0000	1.4
--- libfuncs.h	6 May 2002 13:42:40 -0000
*************** enum libfunc_index
*** 142,147 ****
--- 142,149 ----
  
    LTI_profile_function_entry,
    LTI_profile_function_exit,
+   
+   LTI_find_arc_counters,
  
    LTI_MAX
  };
*************** extern rtx libfunc_table[LTI_MAX];
*** 270,274 ****
--- 272,278 ----
  
  #define profile_function_entry_libfunc	(libfunc_table[LTI_profile_function_entry])
  #define profile_function_exit_libfunc	(libfunc_table[LTI_profile_function_exit])
+ 
+ #define find_arc_counters_libfunc	(libfunc_table[LTI_find_arc_counters])
  
  #endif /* GCC_LIBFUNCS_H */
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	6 May 2002 13:42:41 -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,1420 ----
  #include <errno.h>
  #endif
  
+ #include <gthr.h>
+ 
+ #ifdef __GTHREADS
+ 
+ #ifdef __GTHREAD_MUTEX_INIT
+ #define DECLARE_ARC_COUNTERS_LOCK \
+  static __gthread_mutex_t arc_counters_lock = __GTHREAD_MUTEX_INIT
+ #define INIT_ARC_COUNTERS_LOCK
+ #else
+ #define DECLARE_ARC_COUNTERS_LOCK \
+  static __gthread_mutex_t arc_counters_lock;
+ #define INIT_ARC_COUNTERS_LOCK\
+  __GTHREAD_MUTEX_INIT_FUNCTION (&arc_counters_lock)
+ #endif
+ 
+ #define LOCK_ARC_COUNTERS __gthread_mutex_lock (&arc_counters_lock)
+ #define UNLOCK_ARC_COUNTERS __gthread_mutex_unlock (&arc_counters_lock)
+ 
+ #define DECLARE_ARC_COUNTERS_TSD static __gthread_key_t arc_counters_key
+ 
+ #ifndef THREAD_LIB_SUPPORT
+ #define INIT_ARC_COUNTERS_TSD\
+  __gthread_key_create (&arc_counters_key, __bb_thread_end_func)
+ #else
+ #define INIT_ARC_COUNTERS_TSD\
+  __gthread_key_create (&arc_counters_key, NULL)
+ #endif
+ 
+ #define SET_ARC_COUNTERS_TSD(x)\
+  __gthread_setspecific(arc_counters_key, (x))
+ #define GET_ARC_COUNTERS_TSD\
+  __gthread_getspecific(arc_counters_key)
+ 
+ DECLARE_ARC_COUNTERS_LOCK;
+ DECLARE_ARC_COUNTERS_TSD;
+ 
+ #endif
+ 
  static struct bb *bb_head;
  
+ #ifdef __GTHREADS
+ 
+ int __global_counters = 0, __gthreads_active = 0;
+ static int aofs = 0, moved_static_counters = 0;
+ static gcov_type *arc_counters = (gcov_type *) 0;
+ 
+ #endif
+ 
  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];
! 	}
!     }
! 
! #ifdef __GTHREADS
!   if (arc_counters)
!     {
!       int laofs = aofs;
! 
!       /* propagate counters of main thread to global ones.  */
!       __bb_thread_end_func (GET_ARC_COUNTERS_TSD);
! 
!       /* If we are here for the first time (could be more times due
!          to forking), move results from static counters.  */
!       LOCK_ARC_COUNTERS;
!       if (!moved_static_counters)
! 	{
! 	  for (ptr = bb_head; ptr; ptr = ptr->next)
! 	    {
! 	      int i;
! 	      laofs -= ptr->ncounts;
! 	      for (i = 0; i < ptr->ncounts; i++)
! 		arc_counters[laofs + i] += ptr->counts[i];
! 	      ptr->counts = arc_counters + laofs;
! 	    }
! 	  moved_static_counters = 1;
! 	}
!       UNLOCK_ARC_COUNTERS;
!     }
! 
! #endif
  
+ #ifdef __GTHREADS
+   if (arc_counters)
+     {
+       LOCK_ARC_COUNTERS;
+     }
+ #endif
  
    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,1457 ****
        }
  #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
! __bb_init_func (struct bb *blocks)
  {
    /* User is supposed to check whether the first word is non-0,
       but just in case....  */
  
    if (blocks->zero_word)
      return;
! 
!   /* Initialize destructor.  */
    if (!bb_head)
!     atexit (__bb_exit_func);
  
    /* Set up linked list.  */
    blocks->zero_word = 1;
    blocks->next = bb_head;
    bb_head = blocks;
  }
  
  /* 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;
--- 1440,1652 ----
        }
  #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. */
! 	  __write_long (n_counters_p, da_file, 4);	/* number of counters.  */
! 	  __write_gcov_type (sum_counters_p, da_file, 8);	/* sum of counters.  */
! 	  __write_gcov_type (max_counter_p, da_file, 8);	/* maximal counter.  */
  
! 	  /* per-object statistics. */
! 	  __write_long (ptr->ncounts, da_file, 4);	/* number of counters.  */
! 	  __write_gcov_type (sum_counters_o, da_file, 8);	/* sum of counters.  */
! 	  __write_gcov_type (max_counter_o, da_file, 8);	/* maximal counter.  */
  
! 	  /* 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);
      }
  
! #ifdef __GTHREADS
!   if (arc_counters)
!     {
!       UNLOCK_ARC_COUNTERS;
!     }
! #endif
! }
! 
! /* Called on entry into each profiled function.  Returns (thread-specific)
!    adress of arc counters.  */
! gcov_type *
! __bb_find_arc_counters (void)
! {
! #ifdef __GTHREADS
!    void *arc_counters_tsd = GET_ARC_COUNTERS_TSD;
!    if (!arc_counters_tsd)
!      {
!        arc_counters_tsd = __bb_thread_start_func ();
!      }
!    return ((gcov_type *) arc_counters_tsd);
! #else
!   return (gcov_type *) 0;
! #endif
  }
  
+ #ifdef __GTHREADS
+ 
+ /* Called in a new thread after its creation (from the first attempt to find
+    adress of counter table).  Allocates thread specific counter table.  */
+ 
+ void *
+ __bb_thread_start_func (void)
+ {
+   gcov_type *ret;
+ 
+   if (arc_counters && __gthreads_active)
+     {
+       ret = calloc (aofs, sizeof (gcov_type));
+       SET_ARC_COUNTERS_TSD (ret);
+ 
+       return ret;
+     }
+ 
+   return (void *) 0;
+ }
+ 
+ /* Called in a thread immediatelly before its termination (and after any
+    attempt to modify any counters -- i.e. preferably from thread library
+    (if not supported we use it as a destructor for thread specific data;
+    this would not work if other profiled destructors are called afterwards,
+    so in this case all other destructors must be declared no_profile)).
+    Propagates changes to global counters.  */
  void
! __bb_thread_end_func (void *data)
! {
!   gcov_type *tsd = data;
!   int i;
! 
!   if (!data) return;
!  
!   LOCK_ARC_COUNTERS;
!   for (i=0; i<aofs; i++)
!     arc_counters[i] += tsd[i];
!   UNLOCK_ARC_COUNTERS;
! 
!   free(tsd);
! }
! 
! #else
! 
! void *
! __bb_thread_start_func (void)
! {
!   return (void *) 0;
! }
! 
! #endif
! 
! void
! __bb_init_func (struct bb *blocks, int *offset)
  {
    /* User is supposed to check whether the first word is non-0,
       but just in case....  */
  
    if (blocks->zero_word)
      return;
!   
!   /* Initialize destructor and per-thread data.  */
    if (!bb_head)
!     {
!       atexit (__bb_exit_func);
! #ifdef __GTHREADS
!       if (offset && __gthread_active_p ())
!         {
!           INIT_ARC_COUNTERS_TSD;
!           INIT_ARC_COUNTERS_LOCK;
!           __gthreads_active = 1;
!         }
! #endif
!     }
  
    /* Set up linked list.  */
    blocks->zero_word = 1;
    blocks->next = bb_head;
    bb_head = blocks;
+ 
+ #ifdef __GTHREADS
+   if (offset && __gthreads_active)
+     {
+       *offset = aofs;
+       aofs += blocks->ncounts;
+       arc_counters = realloc (arc_counters, aofs * sizeof (gcov_type));
+       memset (arc_counters + aofs - blocks->ncounts, 0,
+               blocks->ncounts * sizeof (gcov_type));
+     }
+ #endif
  }
  
  /* 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	6 May 2002 13:42:42 -0000
*************** extern void __eprintf (const char *, con
*** 29,39 ****
  
  struct bb;
  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 *);
--- 29,49 ----
  
  struct bb;
  extern void __bb_exit_func (void);
! extern void __bb_init_func (struct bb *, int *);
! extern void *__bb_thread_start_func (void);
! extern void __bb_thread_end_func (void *);
  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);
+ 
+ #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	6 May 2002 13:42:43 -0000
*************** Software Foundation, 59 Temple Place - S
*** 49,54 ****
--- 49,57 ----
  #include "basic-block.h"
  #include "gcov-io.h"
  #include "target.h"
+ #include "profile.h"
+ #include "libfuncs.h"
+ #include "gthr.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.  */
  
--- 95,100 ----
*************** static rtx gen_edge_profiler PARAMS ((in
*** 118,130 ****
--- 116,204 ----
  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));
+ static void insert_profiler_initialization PARAMS ((void));
  
  /* If non-zero, we need to output a constructor to set up the
     per-object-file data.  */
  static int need_func_profiler = 0;
  
+ /* Add code to find adress of arc counters.  */
+ static void
+ insert_profiler_initialization ()
+ {
+   char buf[20];
+   rtx seq, tmp, tmpu, fix;
+   rtx static_table, offset, offset_m;
+   rtx use_global, use_global_m;
+   rtx label_no_threads;
+   edge e = ENTRY_BLOCK_PTR->succ;
+ 
+   for (; e; e = e->succ_next)
+     {
+       if (e->flags & EDGE_FALLTHRU)
+ 	break;
+     }
+   if (!e)
+     abort ();
+ 
+   cfun->arc_counters_adress =
+     assign_stack_local (Pmode,
+ 			GET_MODE_SIZE (Pmode), GET_MODE_ALIGNMENT (Pmode));
+ 
+   ASM_GENERATE_INTERNAL_LABEL (buf, "LPBF", 0);
+   offset = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
+   offset_m = gen_rtx_MEM (SImode, offset);
+ 
+   ASM_GENERATE_INTERNAL_LABEL (buf, "LPBX", 2);
+   static_table = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
+ 
+   use_global = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup ("__global_counters"));
+   use_global_m = gen_rtx_MEM (SImode, use_global);
+ 
+   label_no_threads = gen_label_rtx ();
+ 
+   start_sequence ();
+ 
+   /* Store static table adress.  */
+ 
+   emit_move_insn (copy_rtx (cfun->arc_counters_adress),
+ 		  copy_rtx (static_table));
+ 
+   /* If threads are not active, that is all.  */
+ 
+   do_compare_rtx_and_jump (use_global_m, const0_rtx, EQ, 0, SImode,
+ 			   NULL_RTX, NULL_RTX, label_no_threads);
+   fix = get_last_insn ();
+   if (GET_CODE (fix) != JUMP_INSN)
+     abort ();
+   JUMP_LABEL (fix) = label_no_threads;
+ 
+   /* Otherwise, find where arc counters are.  */
+ 
+   tmp = emit_library_call_value (find_arc_counters_libfunc,
+ 				 NULL, LCT_CONST, Pmode, 0);
+   /* Add offset.  */
+   tmpu = expand_simple_binop (Pmode, PLUS,
+ 			      tmp, offset_m,
+ 			      cfun->arc_counters_adress, 0, OPTAB_DIRECT);
+   /* And store it.  */
+   if (tmpu != cfun->arc_counters_adress)
+     emit_move_insn (copy_rtx (cfun->arc_counters_adress), tmpu);
+ 
+   /* Now the label. */
+   fix = emit_label (label_no_threads);
+   LABEL_NUSES (fix) = 1;
+ 
+   seq = gen_sequence ();
+   end_sequence ();
+ 
+   insert_insn_on_edge (seq, e);
+ }
+ 
  /* Add edge instrumentation code to the entire insn chain.
  
     F is the first insn of the chain.
*************** instrument_edges (el)
*** 148,153 ****
--- 222,229 ----
  	  struct edge_info *inf = EDGE_INFO (e);
  	  if (!inf->ignore && !inf->on_tree)
  	    {
+ 	      rtx edge_profiler;
+               
  	      if (e->flags & EDGE_ABNORMAL)
  		abort ();
  	      if (rtl_dump_file)
*************** instrument_edges (el)
*** 155,170 ****
  			 e->src->index, e->dest->index,
  			 EDGE_CRITICAL_P (e) ? " (and split)" : "");
  	      need_func_profiler = 1;
! 	      insert_insn_on_edge (
! 			 gen_edge_profiler (total_num_edges_instrumented
! 					    + num_instr_edges++), e);
  	    }
  	  e = e->succ_next;
  	}
      }
  
    total_num_edges_instrumented += num_instr_edges;
!   count_instrumented_edges = total_num_edges_instrumented;
  
    total_num_blocks_created += num_edges;
    if (rtl_dump_file)
--- 231,248 ----
  			 e->src->index, e->dest->index,
  			 EDGE_CRITICAL_P (e) ? " (and split)" : "");
  	      need_func_profiler = 1;
! 
! 	      edge_profiler = gen_edge_profiler (total_num_edges_instrumented
! 					         + num_instr_edges++);
! 	      insert_insn_on_edge (edge_profiler, e);
  	    }
  	  e = e->succ_next;
  	}
      }
  
+   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 ****
--- 283,448 ----
  }
  
  
+ /* 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_gcov_type (&max_counter_in_run, da_file, 8);	/* read the maximal counter.  */
+ 
+       /* 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 ****
--- 456,463 ----
    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--;
--- 493,505 ----
  	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 ****
--- 756,791 ----
      }
  
    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 ****
--- 811,822 ----
    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 ****
--- 1033,1043 ----
      {
        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);
*************** branch_prob ()
*** 809,814 ****
--- 1089,1100 ----
  
    if (profile_arc_flag)
      {
+ #ifdef __GTHREADS
+       if (!flag_unsafe_profile_arcs)
+         {
+           insert_profiler_initialization ();
+         }
+ #endif
        instrument_edges (el);
        allocate_reg_info (max_reg_num (), FALSE, FALSE);
      }
*************** 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);
  	}
--- 1170,1190 ----
    /* 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 ****
--- 1198,1206 ----
  	  && !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 ****
--- 1213,1221 ----
        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)
--- 1274,1279 ----
*************** 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)
      {
--- 1304,1311 ----
        fclose (bbg_file);
      }
  
!   if (flag_branch_probabilities && da_file)
!     fclose (da_file);
  
    if (rtl_dump_file)
      {
*************** gen_edge_profiler (edgeno)
*** 1090,1099 ****
  
    start_sequence ();
  
!   tmp = force_reg (Pmode, profiler_label);
    tmp = plus_constant (tmp, GCOV_TYPE_SIZE / BITS_PER_UNIT * edgeno);
    mem_ref = validize_mem (gen_rtx_MEM (mode, tmp));
  
    tmp = expand_simple_binop (mode, PLUS, mem_ref, const1_rtx,
  			     mem_ref, 0, OPTAB_WIDEN);
  
--- 1369,1386 ----
  
    start_sequence ();
  
! #ifdef __GTHREADS
!   if (!flag_unsafe_profile_arcs)
!     tmp = force_reg (Pmode, cfun->arc_counters_adress);
!   else
! #endif
!     tmp = force_reg (Pmode, profiler_label);
! 
    tmp = plus_constant (tmp, GCOV_TYPE_SIZE / BITS_PER_UNIT * edgeno);
    mem_ref = validize_mem (gen_rtx_MEM (mode, tmp));
  
+   set_mem_alias_set (mem_ref, new_alias_set ());
+ 
    tmp = expand_simple_binop (mode, PLUS, mem_ref, const1_rtx,
  			     mem_ref, 0, OPTAB_WIDEN);
  
*************** output_func_start_profiler ()
*** 1113,1126 ****
  {
    tree fnname, fndecl;
    char *name;
!   char buf[20];
    const char *cfnname;
!   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.  */
--- 1400,1410 ----
  {
    tree fnname, fndecl;
    char *name;
!   char buf[20], buf1[20] ATTRIBUTE_UNUSED;
    const char *cfnname;
!   rtx table_address, offset_address;
    enum machine_mode mode = mode_for_size (GCOV_TYPE_SIZE, MODE_INT, 0);
    int save_flag_inline_functions = flag_inline_functions;
  
    /* It's either already been output, or we don't need it because we're
       not doing profile-edges.  */
*************** output_func_start_profiler ()
*** 1163,1175 ****
    init_function_start (fndecl, input_filename, lineno);
    (*lang_hooks.decls.pushlevel) (0);
    expand_function_start (fndecl, 0);
  
    /* Actually generate the code to call __bb_init_func.  */
    ASM_GENERATE_INTERNAL_LABEL (buf, "LPBX", 0);
    table_address = force_reg (Pmode,
  			     gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf)));
!   emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__bb_init_func"), LCT_NORMAL,
! 		     mode, 1, table_address, Pmode);
  
    expand_function_end (input_filename, lineno, 0);
    (*lang_hooks.decls.poplevel) (1, 0, 1);
--- 1447,1472 ----
    init_function_start (fndecl, input_filename, lineno);
    (*lang_hooks.decls.pushlevel) (0);
    expand_function_start (fndecl, 0);
+   cfun->no_profile = 1;
  
    /* Actually generate the code to call __bb_init_func.  */
    ASM_GENERATE_INTERNAL_LABEL (buf, "LPBX", 0);
    table_address = force_reg (Pmode,
  			     gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf)));
! #ifdef __GTHREADS
!   if (!flag_unsafe_profile_arcs)
!     {
!       ASM_GENERATE_INTERNAL_LABEL (buf1, "LPBF", 0);
!       offset_address = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf1));
!     }
!   else
! #endif
!     {
!       offset_address = gen_rtx_CONST_INT (Pmode, 0);
!     }
!   emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__bb_init_func"), 0,
! 		     mode, 2, table_address, Pmode,
! 		     offset_address, Pmode);
  
    expand_function_end (input_filename, lineno, 0);
    (*lang_hooks.decls.poplevel) (1, 0, 1);
*************** 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);
--- 1476,1485 ----
Index: profile.h
===================================================================
RCS file: profile.h
diff -N profile.h
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- profile.h	6 May 2002 13:42:43 -0000
***************
*** 0 ****
--- 1,52 ----
+ /* profile.h - Defines data exported from profile.c to other passes.
+    Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ 
+ This file is part of GCC.
+ 
+ GCC 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.
+ 
+ GCC 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 GCC; see the file COPYING.  If not, write to the Free
+ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.  */
+ 
+ #ifndef GCC_PROFILE_H
+ #define GCC_PROFILE_H
+ 
+ struct
+   {
+     /* Used by final, for allocating the proper amount of storage for the
+        instrumented arc execution counts.  */
+ 
+     int count_instrumented_edges;
+ 
+     /* Used by final, for writing correct # of instrumented edges
+        in this function.  */
+ 
+     int count_edges_instrumented_now;
+ 
+     /* Checksum of the cfg. Used for 'identification' of code.
+        Used by final.  */
+ 
+     long current_function_cfg_checksum;
+ 
+     /* Max. value of counter in program corresponding to the profile data
+        for the current function.  */
+ 
+     gcov_type max_counter_in_program;
+ 
+     /* The number of profiles merged to form the profile data for the current
+        function.  */
+     int count_profiles_merged;
+ 
+   } profile_info;
+ 
+ #endif
Index: toplev.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/toplev.c,v
retrieving revision 1.619
diff -c -3 -p -r1.619 toplev.c
*** toplev.c	2 May 2002 17:51:48 -0000	1.619
--- toplev.c	6 May 2002 13:42:55 -0000
*************** static const lang_independent_options f_
*** 1061,1066 ****
--- 1061,1068 ----
     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,
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	6 May 2002 13:43:26 -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: doc/invoke.texi
===================================================================
RCS file: /cvs/gcc/egcs/gcc/doc/invoke.texi,v
retrieving revision 1.141
diff -c -3 -p -r1.141 invoke.texi
*** doc/invoke.texi	30 Apr 2002 16:47:41 -0000	1.141
--- doc/invoke.texi	6 May 2002 13:43:36 -0000
*************** in the following sections.
*** 248,254 ****
  -fdump-tree-original@r{[}-@var{n}@r{]} -fdump-tree-optimized@r{[}-@var{n}@r{]} @gol
  -fdump-tree-inlined@r{[}-@var{n}@r{]} @gol
  -fmem-report @gol
! -fprofile-arcs  -ftest-coverage  -ftime-report @gol
  -g  -g@var{level}  -gcoff  -gdwarf  -gdwarf-1  -gdwarf-1+  -gdwarf-2 @gol
  -ggdb  -gstabs  -gstabs+  -gvms  -gxcoff  -gxcoff+ @gol
  -p  -pg  -print-file-name=@var{library}  -print-libgcc-file-name @gol
--- 248,254 ----
  -fdump-tree-original@r{[}-@var{n}@r{]} -fdump-tree-optimized@r{[}-@var{n}@r{]} @gol
  -fdump-tree-inlined@r{[}-@var{n}@r{]} @gol
  -fmem-report @gol
! -fprofile-arcs  -ftest-coverage  -ftime-report -funsafe-profile-arcs @gol
  -g  -g@var{level}  -gcoff  -gdwarf  -gdwarf-1  -gdwarf-1+  -gdwarf-2 @gol
  -ggdb  -gstabs  -gstabs+  -gvms  -gxcoff  -gxcoff+ @gol
  -p  -pg  -print-file-name=@var{library}  -print-libgcc-file-name @gol
*************** This option makes it possible to estimat
*** 2828,2833 ****
--- 2828,2840 ----
  calculate basic block execution counts.  In general, basic block
  execution counts as provided by @option{-a} do not give enough
  information to estimate all branch probabilities.
+ 
+ @item -funsafe-profile-arcs
+ @opindex funsafe-profile-arcs
+ 
+ By default GCC emits thread safe profiling code, where threading is supported.
+ This adds extra overhead unnecesary for single threaded programs.  Use this
+ option to disable the feature.
  
  @need 2000
  @item -ftest-coverage


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