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-branch] thread safe profiling patch installed


Hi,
I've installed the patch done by Zdenek with few minor cleanups. The main idea
is to introduce per-thread counters so races don't happen.  The pointer
to counters is then obtained by libcall inserted at the beggining of instrumented
function.

Zdenek, can you please check that it is working and fix problems I've
introduced during merging?  I've checked that the code appears to work roughtly
(it is able to profile simple program), but I still suspect problems around.
I guess we also need some documentation in gcc manual for the gthr interface
once the code settles down.

Thanks for the hard job!

Honza

Thu Nov 22 02:24:39 CET 2001  Zdenek Dvorak <rakdver@atrey.karlin.mff.cuni.cz>

	* config/i386/i386.md (movsi_1): Modified.
	* Makefile.in (profile.o): Add dependency on libfuncs.h and gthr.h.
	(XCFLAGS): Add GTHREAD_FLAGS.
	* attribs.c (handle_no_profile_attribute): New static function.
	(c_common_attribute_table): New attribute "no_profile".
	* cfganal.c (fix_position): New static function.
	(flow_call_edges_add): Modified.
	* crtstuff.c: Prevent functions from being profiled.
	* gcov-io.h: Prevent functions from being profiled.
	* gengenrtl.c: Prevent functions from being profiled.
	* function.c (expand_function_start): Set no_profile.
	* 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.  Prevent functions from being profiled.
	(__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".

Index: Makefile.in
===================================================================
RCS file: /cvs/gcc/egcs/gcc/Makefile.in,v
retrieving revision 1.775.2.13
diff -c -3 -p -r1.775.2.13 Makefile.in
*** Makefile.in	2002/01/01 20:26:17	1.775.2.13
--- Makefile.in	2002/01/03 20:42:38
*************** BOOT_LANGUAGES = c @all_boot_languages@
*** 63,70 ****
  # bootstrap compilations.
  # XCFLAGS is used for most compilations but not when using the GCC just built.
  # TCFLAGS is used for compilations with the GCC just built.
! XCFLAGS =
! TCFLAGS =
  CFLAGS = -g
  STAGE1_CFLAGS = -g @stage1_cflags@
  BOOT_CFLAGS = -g -O2
--- 63,70 ----
  # bootstrap compilations.
  # XCFLAGS is used for most compilations but not when using the GCC just built.
  # TCFLAGS is used for compilations with the GCC just built.
! XCFLAGS = ${GTHREAD_FLAGS}
! TCFLAGS = ${GTHREAD_FLAGS}
  CFLAGS = -g
  STAGE1_CFLAGS = -g @stage1_cflags@
  BOOT_CFLAGS = -g -O2
*************** varasm.o : varasm.c $(CONFIG_H) $(SYSTEM
*** 1354,1360 ****
     output.h c-pragma.h toplev.h xcoffout.h debug.h $(GGC_H) $(TM_P_H) \
     $(HASHTAB_H) $(TARGET_H) langhooks.h
  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)
  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 $(PREDICT_H)\
--- 1354,1360 ----
     output.h c-pragma.h toplev.h xcoffout.h debug.h $(GGC_H) $(TM_P_H) \
     $(HASHTAB_H) $(TARGET_H) langhooks.h
  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 gthr.h\
     insn-config.h $(RECOG_H) output.h toplev.h except.h hash.h $(GGC_H) $(TM_P_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 $(PREDICT_H)\
*************** conflict.o : conflict.c $(CONFIG_H) $(SY
*** 1455,1461 ****
  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) \
!    profile.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 \
--- 1455,1461 ----
  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) \
!    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 \
*************** reg-stack.o : reg-stack.c $(CONFIG_H) $(
*** 1549,1555 ****
     varray.h function.h $(TM_P_H)
  predict.o: predict.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h \
     insn-config.h $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h output.h toplev.h \
!    $(RECOG_H) function.h except.h $(EXPR_H) $(TM_P_H) $(PREDICT_H)
  lists.o: lists.c $(CONFIG_H) $(SYSTEM_H) toplev.h $(RTL_H) $(GGC_H)
  bb-reorder.o : bb-reorder.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h \
     $(BASIC_BLOCK_H) hard-reg-set.h output.h cfglayout.h $(FIBHEAP_H)
--- 1549,1555 ----
     varray.h function.h $(TM_P_H)
  predict.o: predict.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h \
     insn-config.h $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h output.h toplev.h \
!    $(RECOG_H) function.h except.h $(EXPR_H) $(TM_P_H) $(PREDICT_H) profile.h
  lists.o: lists.c $(CONFIG_H) $(SYSTEM_H) toplev.h $(RTL_H) $(GGC_H)
  bb-reorder.o : bb-reorder.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h \
     $(BASIC_BLOCK_H) hard-reg-set.h output.h cfglayout.h $(FIBHEAP_H)
Index: attribs.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/attribs.c,v
retrieving revision 1.4.2.1
diff -c -3 -p -r1.4.2.1 attribs.c
*** attribs.c	2001/12/14 23:07:35	1.4.2.1
--- attribs.c	2002/01/03 20:42:39
*************** static tree handle_alias_attribute	PARAM
*** 76,81 ****
--- 76,84 ----
  static tree handle_no_instrument_function_attribute PARAMS ((tree *, tree,
  							     tree, int,
  							     bool *));
+ static tree handle_no_profile_attribute	PARAMS ((tree *, tree,
+ 						 tree, int,
+ 						 bool *));
  static tree handle_malloc_attribute	PARAMS ((tree *, tree, tree, int,
  						 bool *));
  static tree handle_no_limit_stack_attribute PARAMS ((tree *, tree, tree, int,
*************** static const struct attribute_spec c_com
*** 132,137 ****
--- 135,142 ----
  			      handle_alias_attribute },
    { "no_instrument_function", 0, 0, true,  false, false,
  			      handle_no_instrument_function_attribute },
+   { "no_profile",             0, 0, true,  false, false,
+ 			      handle_no_profile_attribute },
    { "malloc",                 0, 0, true,  false, false,
  			      handle_malloc_attribute },
    { "no_stack_limit",         0, 0, true,  false, false,
*************** handle_no_instrument_function_attribute 
*** 1048,1053 ****
--- 1053,1089 ----
      }
    else
      DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1;
+ 
+   return NULL_TREE;
+ }
+ 
+ /* Handle a "no_profile" attribute; arguments as in
+    struct attribute_spec.handler.  */
+ 
+ static tree
+ handle_no_profile_attribute (node, name, args, flags, no_add_attrs)
+      tree *node;
+      tree name;
+      tree args ATTRIBUTE_UNUSED;
+      int flags ATTRIBUTE_UNUSED;
+      bool *no_add_attrs;
+ {
+   tree decl = *node;
+ 
+   if (TREE_CODE (decl) != FUNCTION_DECL)
+     {
+       error_with_decl (decl,
+ 		       "`%s' attribute applies only to functions",
+ 		       IDENTIFIER_POINTER (name));
+       *no_add_attrs = true;
+     }
+   else if (DECL_INITIAL (decl))
+     {
+       error_with_decl (decl,
+ 		       "can't set `%s' attribute after definition",
+ 		       IDENTIFIER_POINTER (name));
+       *no_add_attrs = true;
+     }
  
    return NULL_TREE;
  }
Index: basic-block.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/basic-block.h,v
retrieving revision 1.127.2.6
diff -c -3 -p -r1.127.2.6 basic-block.h
*** basic-block.h	2001/12/29 16:52:51	1.127.2.6
--- basic-block.h	2002/01/03 20:42:39
*************** extern edge split_block			PARAMS ((basic
*** 299,304 ****
--- 299,305 ----
  extern basic_block split_edge		PARAMS ((edge));
  extern void insert_insn_on_edge		PARAMS ((rtx, edge));
  extern void commit_edge_insertions	PARAMS ((void));
+ extern void commit_edge_insertions_watch_calls	PARAMS ((void));
  extern void remove_fake_edges		PARAMS ((void));
  extern void add_noreturn_fake_exit_edges	PARAMS ((void));
  extern void connect_infinite_loops_to_exit	PARAMS ((void));
Index: cfgrtl.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cfgrtl.c,v
retrieving revision 1.10.2.10
diff -c -3 -p -r1.10.2.10 cfgrtl.c
*** cfgrtl.c	2001/12/29 23:46:36	1.10.2.10
--- cfgrtl.c	2002/01/03 20:42:42
*************** rtx tail_recursion_label_list;
*** 74,80 ****
  
  static int can_delete_note_p		PARAMS ((rtx));
  static int can_delete_label_p		PARAMS ((rtx));
! static void commit_one_edge_insertion	PARAMS ((edge));
  static bool try_redirect_by_replacing_jump PARAMS ((edge, basic_block));
  static rtx last_loop_beg_note		PARAMS ((rtx));
  static bool back_edge_of_syntactic_loop_p PARAMS ((basic_block, basic_block));
--- 74,80 ----
  
  static int can_delete_note_p		PARAMS ((rtx));
  static int can_delete_label_p		PARAMS ((rtx));
! static void commit_one_edge_insertion	PARAMS ((edge, int));
  static bool try_redirect_by_replacing_jump PARAMS ((edge, basic_block));
  static rtx last_loop_beg_note		PARAMS ((rtx));
  static bool back_edge_of_syntactic_loop_p PARAMS ((basic_block, basic_block));
*************** insert_insn_on_edge (pattern, e)
*** 1220,1227 ****
  /* Update the CFG for the instructions queued on edge E.  */
  
  static void
! commit_one_edge_insertion (e)
       edge e;
  {
    rtx before = NULL_RTX, after = NULL_RTX, insns, tmp, last;
    basic_block bb;
--- 1220,1228 ----
  /* Update the CFG for the instructions queued on edge E.  */
  
  static void
! commit_one_edge_insertion (e, watch_calls)
       edge e;
+      int watch_calls;
  {
    rtx before = NULL_RTX, after = NULL_RTX, insns, tmp, last;
    basic_block bb;
*************** commit_one_edge_insertion (e)
*** 1230,1292 ****
    insns = e->insns;
    e->insns = NULL_RTX;
  
!   /* Figure out where to put these things.  If the destination has
!      one predecessor, insert there.  Except for the exit block.  */
!   if (e->dest->pred->pred_next == NULL
!       && e->dest != EXIT_BLOCK_PTR)
!     {
!       bb = e->dest;
! 
!       /* Get the location correct wrt a code label, and "nice" wrt
! 	 a basic block note, and before everything else.  */
!       tmp = bb->head;
!       if (GET_CODE (tmp) == CODE_LABEL)
! 	tmp = NEXT_INSN (tmp);
!       if (NOTE_INSN_BASIC_BLOCK_P (tmp))
! 	tmp = NEXT_INSN (tmp);
!       if (tmp == bb->head)
! 	before = tmp;
!       else
! 	after = PREV_INSN (tmp);
!     }
  
!   /* If the source has one successor and the edge is not abnormal,
!      insert there.  Except for the entry block.  */
!   else if ((e->flags & EDGE_ABNORMAL) == 0
! 	   && e->src->succ->succ_next == NULL
! 	   && e->src != ENTRY_BLOCK_PTR)
!     {
!       bb = e->src;
! 
!       /* It is possible to have a non-simple jump here.  Consider a target
! 	 where some forms of unconditional jumps clobber a register.  This
! 	 happens on the fr30 for example.
! 
! 	 We know this block has a single successor, so we can just emit
! 	 the queued insns before the jump.  */
!       if (GET_CODE (bb->end) == JUMP_INSN)
! 	for (before = bb->end;
! 	     GET_CODE (PREV_INSN (before)) == NOTE
! 	     && NOTE_LINE_NUMBER (PREV_INSN (before)) == NOTE_INSN_LOOP_BEG;
! 	     before = PREV_INSN (before))
! 	  ;
!       else
  	{
! 	  /* We'd better be fallthru, or we've lost track of what's what.  */
! 	  if ((e->flags & EDGE_FALLTHRU) == 0)
! 	    abort ();
  
  	  after = bb->end;
  	}
      }
  
-   /* Otherwise we must split the edge.  */
-   else
-     {
-       bb = split_edge (e);
-       after = bb->end;
-     }
- 
    /* Now that we've found the spot, do the insertion.  */
  
    if (before)
--- 1231,1338 ----
    insns = e->insns;
    e->insns = NULL_RTX;
  
!   /* Special case -- avoid inserting code between call and storing
!      its return value.  */
!   if (watch_calls
!       && (e->flags & EDGE_FALLTHRU)
!       && !e->dest->pred->pred_next)
!     {
!       rtx insert_after = e->src->end;
!       if (insert_after
!           && SMALL_REGISTER_CLASSES
!           && GET_CODE (insert_after) == CALL_INSN
!           && (GET_CODE (PATTERN (insert_after)) == SET
!            || (GET_CODE (PATTERN (insert_after)) == PARALLEL
!             && GET_CODE (XVECEXP (PATTERN (insert_after), 0, 0)) == SET)))
!         {
!           rtx return_reg;
!           rtx next_insert_after = next_nonnote_insn (insert_after);
! 
!           /* The first insn after the call may be a stack pop, skip it.  */
!           if (next_insert_after
!               && GET_CODE (next_insert_after) == INSN
!               && GET_CODE (PATTERN (next_insert_after)) == SET
!               && SET_DEST (PATTERN (next_insert_after)) == stack_pointer_rtx)
!             next_insert_after = next_nonnote_insn (next_insert_after);
!           if (next_insert_after
!               && GET_CODE (next_insert_after) == INSN)
!             {
!               if (GET_CODE (PATTERN (insert_after)) == SET)
!                 return_reg = SET_DEST (PATTERN (insert_after));
!               else
!                 return_reg = SET_DEST (XVECEXP (PATTERN (insert_after), 0, 0));
! 
!               /* Now, NEXT_INSERT_AFTER may be an instruction that uses the
!                  return value.  However, it could also be something else,
!                  like a CODE_LABEL, so check that the code is INSN.  */
!               if (next_insert_after
!                   && GET_RTX_CLASS (GET_CODE (next_insert_after)) == 'i'
!                   && reg_referenced_p (return_reg, PATTERN (next_insert_after)))
!                 insert_after = next_insert_after;
!             }
!           after = insert_after;
!           bb = e->dest;
!         }
!     }
!   if (!before && !after)
!     {
!       /* Figure out where to put these things.  If the destination has
! 	 one predecessor, insert there.  Except for the exit block.  */
!       if (e->dest->pred->pred_next == NULL
! 	  && e->dest != EXIT_BLOCK_PTR)
! 	{
! 	  bb = e->dest;
  
! 	  /* Get the location correct wrt a code label, and "nice" wrt
! 	     a basic block note, and before everything else.  */
! 	  tmp = bb->head;
! 	  if (GET_CODE (tmp) == CODE_LABEL)
! 	    tmp = NEXT_INSN (tmp);
! 	  if (NOTE_INSN_BASIC_BLOCK_P (tmp))
! 	    tmp = NEXT_INSN (tmp);
! 	  if (tmp == bb->head)
! 	    before = tmp;
! 	  else
! 	    after = PREV_INSN (tmp);
! 	}
! 
!       /* If the source has one successor and the edge is not abnormal,
! 	 insert there.  Except for the entry block.  */
!       else if ((e->flags & EDGE_ABNORMAL) == 0
! 	       && e->src->succ->succ_next == NULL
! 	       && e->src != ENTRY_BLOCK_PTR)
  	{
! 	  bb = e->src;
! 
! 	  /* It is possible to have a non-simple jump here.  Consider a target
! 	     where some forms of unconditional jumps clobber a register.  This
! 	     happens on the fr30 for example.
! 
! 	     We know this block has a single successor, so we can just emit
! 	     the queued insns before the jump.  */
! 	  if (GET_CODE (bb->end) == JUMP_INSN)
! 	    for (before = bb->end;
! 		 GET_CODE (PREV_INSN (before)) == NOTE
! 		 && NOTE_LINE_NUMBER (PREV_INSN (before)) == NOTE_INSN_LOOP_BEG;
! 		 before = PREV_INSN (before))
! 	      ;
! 	  else
! 	    {
! 	      /* We'd better be fallthru, or we've lost track of what's what.  */
! 	      if ((e->flags & EDGE_FALLTHRU) == 0)
! 		abort ();
  
+ 	      after = bb->end;
+ 	    }
+ 	}
+       /* Otherwise we must split the edge.  */
+       else
+ 	{
+ 	  bb = split_edge (e);
  	  after = bb->end;
  	}
      }
  
    /* Now that we've found the spot, do the insertion.  */
  
    if (before)
*************** commit_edge_insertions ()
*** 1343,1350 ****
        for (e = bb->succ; e; e = next)
  	{
  	  next = e->succ_next;
  	  if (e->insns)
! 	    commit_one_edge_insertion (e);
  	}
  
        if (++i >= n_basic_blocks)
--- 1389,1428 ----
        for (e = bb->succ; e; e = next)
  	{
  	  next = e->succ_next;
+ 	  if (e->insns)
+ 	    commit_one_edge_insertion (e, false);
+ 	}
+ 
+       if (++i >= n_basic_blocks)
+ 	break;
+       bb = BASIC_BLOCK (i);
+     }
+ }
+ 
+ /* Update the CFG for all queued instructions, taking special care of inserting
+    code on edges between call and storing its return value.  */
+ 
+ void
+ commit_edge_insertions_watch_calls ()
+ {
+   int i;
+   basic_block bb;
+ 
+ #ifdef ENABLE_CHECKING
+   verify_flow_info ();
+ #endif
+ 
+   i = -1;
+   bb = ENTRY_BLOCK_PTR;
+   while (1)
+     {
+       edge e, next;
+ 
+       for (e = bb->succ; e; e = next)
+ 	{
+ 	  next = e->succ_next;
  	  if (e->insns)
! 	    commit_one_edge_insertion (e, true);
  	}
  
        if (++i >= n_basic_blocks)
Index: crtstuff.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/crtstuff.c,v
retrieving revision 1.50.2.1
diff -c -3 -p -r1.50.2.1 crtstuff.c
*** crtstuff.c	2001/12/29 16:53:16	1.50.2.1
--- crtstuff.c	2002/01/03 20:42:42
*************** extern void __cxa_finalize (void *) TARG
*** 237,243 ****
     the list we left off processing, and we resume at that point,
     should we be re-invoked.  */
  
! static void
  __do_global_dtors_aux (void)
  {
    static func_ptr *p = __DTOR_LIST__ + 1;
--- 237,243 ----
     the list we left off processing, and we resume at that point,
     should we be re-invoked.  */
  
! static void __attribute__ ((__no_profile__))
  __do_global_dtors_aux (void)
  {
    static func_ptr *p = __DTOR_LIST__ + 1;
*************** __do_global_dtors_aux (void)
*** 276,282 ****
  
  /* Stick a call to __do_global_dtors_aux into the .fini section.  */
  
! static void __attribute__ ((__unused__))
  fini_dummy (void)
  {
    asm (FINI_SECTION_ASM_OP);
--- 276,282 ----
  
  /* Stick a call to __do_global_dtors_aux into the .fini section.  */
  
! static void __attribute__ ((__unused__)) __attribute__ ((__no_profile__))
  fini_dummy (void)
  {
    asm (FINI_SECTION_ASM_OP);
*************** fini_dummy (void)
*** 292,298 ****
     reason calls with no arguments work more reliably in .init, so stick the
     call in another function.  */
  
! static void
  frame_dummy (void)
  {
  #ifdef USE_EH_FRAME_REGISTRY
--- 292,298 ----
     reason calls with no arguments work more reliably in .init, so stick the
     call in another function.  */
  
! static void __attribute__ ((__no_profile__))
  frame_dummy (void)
  {
  #ifdef USE_EH_FRAME_REGISTRY
*************** frame_dummy (void)
*** 322,328 ****
  #endif /* JCR_SECTION_NAME */
  }
  
! static void __attribute__ ((__unused__))
  init_dummy (void)
  {
    asm (INIT_SECTION_ASM_OP);
--- 322,328 ----
  #endif /* JCR_SECTION_NAME */
  }
  
! static void __attribute__ ((__unused__)) __attribute__ ((__no_profile__))
  init_dummy (void)
  {
    asm (INIT_SECTION_ASM_OP);
*************** init_dummy (void)
*** 343,350 ****
     INVOKE__main is defined.  This has the additional effect of forcing cc1
     to switch to the .text section.  */
  
! static void __do_global_ctors_aux (void);
! void
  __do_global_ctors (void)
  {
  #ifdef INVOKE__main
--- 343,350 ----
     INVOKE__main is defined.  This has the additional effect of forcing cc1
     to switch to the .text section.  */
  
! static void __do_global_ctors_aux (void) __attribute__ ((__no_profile__));
! void __attribute__ ((__no_profile__))
  __do_global_ctors (void)
  {
  #ifdef INVOKE__main
*************** asm (INIT_SECTION_ASM_OP);	/* cc1 doesn'
*** 373,379 ****
     such a thing) so that we can properly perform the construction of
     file-scope static-storage C++ objects within shared libraries.  */
  
! static void
  __do_global_ctors_aux (void)	/* prologue goes in .init section */
  {
  #ifdef FORCE_INIT_SECTION_ALIGN
--- 373,379 ----
     such a thing) so that we can properly perform the construction of
     file-scope static-storage C++ objects within shared libraries.  */
  
! static void __attribute__ ((__no_profile__))
  __do_global_ctors_aux (void)	/* prologue goes in .init section */
  {
  #ifdef FORCE_INIT_SECTION_ALIGN
*************** __do_global_ctors_aux (void)	/* prologue
*** 392,398 ****
     not an SVR4-style .fini section.  __do_global_dtors can be non-static
     in this case because we protect it with -hidden_symbol.  */
  
! void
  __do_global_dtors (void)
  {
    func_ptr *p, f;
--- 392,398 ----
     not an SVR4-style .fini section.  __do_global_dtors can be non-static
     in this case because we protect it with -hidden_symbol.  */
  
! void __attribute__ ((__no_profile__))
  __do_global_dtors (void)
  {
    func_ptr *p, f;
*************** __do_global_dtors (void)
*** 410,416 ****
     in crtbegin.o, we can reference a couple of symbols not visible there.
     Plus, since we're before libgcc.a, we have no problems referencing
     functions from there.  */
! void
  __do_global_ctors_1(void)
  {
  #ifdef USE_EH_FRAME_REGISTRY
--- 410,416 ----
     in crtbegin.o, we can reference a couple of symbols not visible there.
     Plus, since we're before libgcc.a, we have no problems referencing
     functions from there.  */
! void __attribute__ ((__no_profile__))
  __do_global_ctors_1(void)
  {
  #ifdef USE_EH_FRAME_REGISTRY
*************** STATIC void *__JCR_END__[1] 
*** 487,493 ****
  
  #ifdef OBJECT_FORMAT_ELF
  
! static void
  __do_global_ctors_aux (void)
  {
    func_ptr *p;
--- 487,493 ----
  
  #ifdef OBJECT_FORMAT_ELF
  
! static void __attribute__ ((__no_profile__))
  __do_global_ctors_aux (void)
  {
    func_ptr *p;
*************** __do_global_ctors_aux (void)
*** 497,503 ****
  
  /* Stick a call to __do_global_ctors_aux into the .init section.  */
  
! static void __attribute__ ((__unused__))
  init_dummy (void)
  {
    asm (INIT_SECTION_ASM_OP);
--- 497,503 ----
  
  /* Stick a call to __do_global_ctors_aux into the .init section.  */
  
! static void __attribute__ ((__unused__)) __attribute__ ((__no_profile__))
  init_dummy (void)
  {
    asm (INIT_SECTION_ASM_OP);
*************** init_dummy (void)
*** 534,540 ****
     the state of the floating-point coprocessor, etc.) which should be done
     before we start to execute any of the user's code.  */
  
! static void
  __do_global_ctors_aux (void)	/* prologue goes in .text section */
  {
    asm (INIT_SECTION_ASM_OP);
--- 534,540 ----
     the state of the floating-point coprocessor, etc.) which should be done
     before we start to execute any of the user's code.  */
  
! static void __attribute__ ((__no_profile__))
  __do_global_ctors_aux (void)	/* prologue goes in .text section */
  {
    asm (INIT_SECTION_ASM_OP);
*************** asm (TEXT_SECTION_ASM_OP);
*** 556,562 ****
     not an SVR4-style .init section.  __do_global_ctors can be non-static
     in this case because we protect it with -hidden_symbol.  */
  extern void __do_global_ctors_1(void);
! void
  __do_global_ctors (void)
  {
    func_ptr *p;
--- 556,562 ----
     not an SVR4-style .init section.  __do_global_ctors can be non-static
     in this case because we protect it with -hidden_symbol.  */
  extern void __do_global_ctors_1(void);
! void __attribute__ ((__no_profile__))
  __do_global_ctors (void)
  {
    func_ptr *p;
*************** extern const struct section *
*** 602,608 ****
  
  static void __reg_frame_ctor (void) __attribute__ ((constructor));
  
! static void
  __reg_frame_ctor (void)
  {
    static struct object object;
--- 602,608 ----
  
  static void __reg_frame_ctor (void) __attribute__ ((constructor));
  
! static void __attribute__ ((__no_profile__))
  __reg_frame_ctor (void)
  {
    static struct object object;
*************** __reg_frame_ctor (void)
*** 617,623 ****
  
  static void __dereg_frame_dtor (void) __attribute__ ((destructor));
  
! static void
  __dereg_frame_dtor (void)
  {
    const struct section *eh_frame;
--- 617,623 ----
  
  static void __dereg_frame_dtor (void) __attribute__ ((destructor));
  
! static void __attribute__ ((__no_profile__))
  __dereg_frame_dtor (void)
  {
    const struct section *eh_frame;
Index: final.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/final.c,v
retrieving revision 1.220.2.5
diff -c -3 -p -r1.220.2.5 final.c
*** final.c	2002/01/01 20:26:18	1.220.2.5
--- final.c	2002/01/03 20:42:44
*************** end_final (filename)
*** 346,351 ****
--- 346,359 ----
        assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name),
  	  pointer_bytes, align2, 1);
  
+       /* Offset to table of arc counters.  */
+       if (profile_arc_flag)
+         {
+           ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBF", 0);
+           assemble_integer (const0_rtx, long_bytes, align2, 1);
+         }
+ 
+ 
        /* Output the file name changing the suffix to .d for
  	 Sun tcov compatibility.  */
        ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 1);
Index: flags.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/flags.h,v
retrieving revision 1.70.2.2
diff -c -3 -p -r1.70.2.2 flags.h
*** flags.h	2001/12/29 16:53:29	1.70.2.2
--- flags.h	2002/01/03 20:42:44
*************** extern int profile_flag;
*** 177,182 ****
--- 177,187 ----
  
  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.322.2.4
diff -c -3 -p -r1.322.2.4 function.c
*** function.c	2001/12/29 16:53:33	1.322.2.4
--- function.c	2002/01/03 20:42:48
*************** Software Foundation, 59 Temple Place - S
*** 59,64 ****
--- 59,65 ----
  #include "ggc.h"
  #include "tm_p.h"
  #include "integrate.h"
+ #include "gthr.h"
  
  #ifndef TRAMPOLINE_ALIGNMENT
  #define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY
*************** expand_main_function ()
*** 6338,6343 ****
--- 6339,6358 ----
    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_
*** 6385,6390 ****
--- 6400,6409 ----
    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_limit_stack
      = (stack_limit_rtx != NULL_RTX && ! DECL_NO_LIMIT_STACK (subr));
Index: function.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/function.h,v
retrieving revision 1.71.2.2
diff -c -3 -p -r1.71.2.2 function.h
*** function.h	2001/12/20 21:15:06	1.71.2.2
--- function.h	2002/01/03 20:42:48
*************** struct function
*** 382,387 ****
--- 382,390 ----
       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
*** 433,438 ****
--- 436,444 ----
    /* 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 stack limit checking should be enabled in the current
       function.  */
Index: gcov-io.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/gcov-io.h,v
retrieving revision 1.14.2.1
diff -c -3 -p -r1.14.2.1 gcov-io.h
*** gcov-io.h	2002/01/01 20:26:18	1.14.2.1
--- gcov-io.h	2002/01/03 20:42:49
*************** Software Foundation, 59 Temple Place - S
*** 24,38 ****
  #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.  */
  
--- 24,47 ----
  #include <stdio.h>
  #include <sys/types.h>
  
! static int __fetch_long	PARAMS ((long *, char *, size_t))
!   ATTRIBUTE_UNUSED ATTRIBUTE_NO_PROFILE;
! static int __read_long  PARAMS ((long *, FILE *, size_t))
!   ATTRIBUTE_UNUSED ATTRIBUTE_NO_PROFILE;
! static int __write_long PARAMS ((long, FILE *, size_t))
!   ATTRIBUTE_UNUSED ATTRIBUTE_NO_PROFILE;
! static int __fetch_gcov_type PARAMS ((gcov_type *, char *, size_t))
!   ATTRIBUTE_UNUSED ATTRIBUTE_NO_PROFILE;
! static int __store_gcov_type PARAMS ((gcov_type, char *, size_t))
!   ATTRIBUTE_UNUSED ATTRIBUTE_NO_PROFILE;
! static int __read_gcov_type  PARAMS ((gcov_type *, FILE *, size_t))
!   ATTRIBUTE_UNUSED ATTRIBUTE_NO_PROFILE;
! static int __write_gcov_type PARAMS ((gcov_type, FILE *, size_t))
!   ATTRIBUTE_UNUSED ATTRIBUTE_NO_PROFILE;
! static int __write_gcov_string PARAMS ((const char *, size_t, FILE*, long))
!   ATTRIBUTE_UNUSED ATTRIBUTE_NO_PROFILE;
! static int __read_gcov_string PARAMS ((char *, size_t, FILE*, long))
!   ATTRIBUTE_UNUSED ATTRIBUTE_NO_PROFILE;
  
  /* These routines only work for signed values.  */
  
Index: libfuncs.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/libfuncs.h,v
retrieving revision 1.2.8.1
diff -c -3 -p -r1.2.8.1 libfuncs.h
*** libfuncs.h	2001/12/14 23:08:18	1.2.8.1
--- libfuncs.h	2002/01/03 20:42:50
*************** enum libfunc_index
*** 141,146 ****
--- 141,148 ----
  
    LTI_profile_function_entry,
    LTI_profile_function_exit,
+   
+   LTI_find_arc_counters,
  
    LTI_MAX
  };
*************** extern rtx libfunc_table[LTI_MAX];
*** 268,272 ****
--- 270,276 ----
  
  #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.127.2.5
diff -c -3 -p -r1.127.2.5 libgcc2.c
*** libgcc2.c	2002/01/01 20:26:18	1.127.2.5
--- libgcc2.c	2002/01/03 20:42:50
*************** Software Foundation, 59 Temple Place - S
*** 49,55 ****
  #if defined (L_divdi3) || defined (L_moddi3)
  static inline
  #endif
! DWtype
  __negdi2 (DWtype u)
  {
    DWunion w;
--- 49,55 ----
  #if defined (L_divdi3) || defined (L_moddi3)
  static inline
  #endif
! DWtype __attribute__ ((__no_profile__))
  __negdi2 (DWtype u)
  {
    DWunion w;
*************** __negdi2 (DWtype u)
*** 65,71 ****
  #endif
  
  #ifdef L_addvsi3
! Wtype
  __addvsi3 (Wtype a, Wtype b)
  {
    Wtype w;
--- 65,71 ----
  #endif
  
  #ifdef L_addvsi3
! Wtype __attribute__ ((__no_profile__))
  __addvsi3 (Wtype a, Wtype b)
  {
    Wtype w;
*************** __addvsi3 (Wtype a, Wtype b)
*** 80,86 ****
  #endif
  
  #ifdef L_addvdi3
! DWtype
  __addvdi3 (DWtype a, DWtype b)
  {
    DWtype w;
--- 80,86 ----
  #endif
  
  #ifdef L_addvdi3
! DWtype __attribute__ ((__no_profile__))
  __addvdi3 (DWtype a, DWtype b)
  {
    DWtype w;
*************** __addvdi3 (DWtype a, DWtype b)
*** 95,101 ****
  #endif
  
  #ifdef L_subvsi3
! Wtype
  __subvsi3 (Wtype a, Wtype b)
  {
  #ifdef L_addvsi3
--- 95,101 ----
  #endif
  
  #ifdef L_subvsi3
! Wtype __attribute__ ((__no_profile__))
  __subvsi3 (Wtype a, Wtype b)
  {
  #ifdef L_addvsi3
*************** __subvsi3 (Wtype a, Wtype b)
*** 114,120 ****
  #endif
  
  #ifdef L_subvdi3
! DWtype
  __subvdi3 (DWtype a, DWtype b)
  {
  #ifdef L_addvdi3
--- 114,120 ----
  #endif
  
  #ifdef L_subvdi3
! DWtype __attribute__ ((__no_profile__))
  __subvdi3 (DWtype a, DWtype b)
  {
  #ifdef L_addvdi3
*************** __subvdi3 (DWtype a, DWtype b)
*** 133,139 ****
  #endif
  
  #ifdef L_mulvsi3
! Wtype
  __mulvsi3 (Wtype a, Wtype b)
  {
    DWtype w;
--- 133,139 ----
  #endif
  
  #ifdef L_mulvsi3
! Wtype __attribute__ ((__no_profile__))
  __mulvsi3 (Wtype a, Wtype b)
  {
    DWtype w;
*************** __mulvsi3 (Wtype a, Wtype b)
*** 148,154 ****
  #endif
  
  #ifdef L_negvsi2
! Wtype
  __negvsi2 (Wtype a)
  {
     Wtype w;
--- 148,154 ----
  #endif
  
  #ifdef L_negvsi2
! Wtype __attribute__ ((__no_profile__))
  __negvsi2 (Wtype a)
  {
     Wtype w;
*************** __negvsi2 (Wtype a)
*** 163,169 ****
  #endif
  
  #ifdef L_negvdi2
! DWtype
  __negvdi2 (DWtype a)
  {
     DWtype w;
--- 163,169 ----
  #endif
  
  #ifdef L_negvdi2
! DWtype __attribute__ ((__no_profile__))
  __negvdi2 (DWtype a)
  {
     DWtype w;
*************** __negvdi2 (DWtype a)
*** 178,184 ****
  #endif
  
  #ifdef L_absvsi2
! Wtype
  __absvsi2 (Wtype a)
  {
     Wtype w = a;
--- 178,184 ----
  #endif
  
  #ifdef L_absvsi2
! Wtype __attribute__ ((__no_profile__))
  __absvsi2 (Wtype a)
  {
     Wtype w = a;
*************** __absvsi2 (Wtype a)
*** 198,204 ****
  #endif
  
  #ifdef L_absvdi2
! DWtype
  __absvdi2 (DWtype a)
  {
     DWtype w = a;
--- 198,204 ----
  #endif
  
  #ifdef L_absvdi2
! DWtype __attribute__ ((__no_profile__))
  __absvdi2 (DWtype a)
  {
     DWtype w = a;
*************** __absvdi2 (DWtype a)
*** 218,224 ****
  #endif
  
  #ifdef L_mulvdi3
! DWtype
  __mulvdi3 (DWtype u, DWtype v)
  {
     DWtype w;
--- 218,224 ----
  #endif
  
  #ifdef L_mulvdi3
! DWtype __attribute__ ((__no_profile__))
  __mulvdi3 (DWtype u, DWtype v)
  {
     DWtype w;
*************** __mulvdi3 (DWtype u, DWtype v)
*** 236,242 ****
  /* Unless shift functions are defined whith full ANSI prototypes,
     parameter b will be promoted to int if word_type is smaller than an int.  */
  #ifdef L_lshrdi3
! DWtype
  __lshrdi3 (DWtype u, word_type b)
  {
    DWunion w;
--- 236,242 ----
  /* Unless shift functions are defined whith full ANSI prototypes,
     parameter b will be promoted to int if word_type is smaller than an int.  */
  #ifdef L_lshrdi3
! DWtype __attribute__ ((__no_profile__))
  __lshrdi3 (DWtype u, word_type b)
  {
    DWunion w;
*************** __lshrdi3 (DWtype u, word_type b)
*** 267,273 ****
  #endif
  
  #ifdef L_ashldi3
! DWtype
  __ashldi3 (DWtype u, word_type b)
  {
    DWunion w;
--- 267,273 ----
  #endif
  
  #ifdef L_ashldi3
! DWtype __attribute__ ((__no_profile__))
  __ashldi3 (DWtype u, word_type b)
  {
    DWunion w;
*************** __ashldi3 (DWtype u, word_type b)
*** 298,304 ****
  #endif
  
  #ifdef L_ashrdi3
! DWtype
  __ashrdi3 (DWtype u, word_type b)
  {
    DWunion w;
--- 298,304 ----
  #endif
  
  #ifdef L_ashrdi3
! DWtype __attribute__ ((__no_profile__))
  __ashrdi3 (DWtype u, word_type b)
  {
    DWunion w;
*************** __ashrdi3 (DWtype u, word_type b)
*** 330,336 ****
  #endif
  
  #ifdef L_ffsdi2
! DWtype
  __ffsdi2 (DWtype u)
  {
    DWunion uu;
--- 330,336 ----
  #endif
  
  #ifdef L_ffsdi2
! DWtype __attribute__ ((__no_profile__))
  __ffsdi2 (DWtype u)
  {
    DWunion uu;
*************** __ffsdi2 (DWtype u)
*** 350,356 ****
  #endif
  
  #ifdef L_muldi3
! DWtype
  __muldi3 (DWtype u, DWtype v)
  {
    DWunion w;
--- 350,356 ----
  #endif
  
  #ifdef L_muldi3
! DWtype __attribute__ ((__no_profile__))
  __muldi3 (DWtype u, DWtype v)
  {
    DWunion w;
*************** __muldi3 (DWtype u, DWtype v)
*** 369,375 ****
  
  #ifdef L_udiv_w_sdiv
  #if defined (sdiv_qrnnd)
! UWtype
  __udiv_w_sdiv (UWtype *rp, UWtype a1, UWtype a0, UWtype d)
  {
    UWtype q, r;
--- 369,375 ----
  
  #ifdef L_udiv_w_sdiv
  #if defined (sdiv_qrnnd)
! UWtype __attribute__ ((__no_profile__))
  __udiv_w_sdiv (UWtype *rp, UWtype a1, UWtype a0, UWtype d)
  {
    UWtype q, r;
*************** __udiv_w_sdiv (UWtype *rp, UWtype a1, UW
*** 467,473 ****
  }
  #else
  /* If sdiv_qrnnd doesn't exist, define dummy __udiv_w_sdiv.  */
! UWtype
  __udiv_w_sdiv (UWtype *rp __attribute__ ((__unused__)),
  	       UWtype a1 __attribute__ ((__unused__)),
  	       UWtype a0 __attribute__ ((__unused__)),
--- 467,473 ----
  }
  #else
  /* If sdiv_qrnnd doesn't exist, define dummy __udiv_w_sdiv.  */
! UWtype __attribute__ ((__no_profile__))
  __udiv_w_sdiv (UWtype *rp __attribute__ ((__unused__)),
  	       UWtype a1 __attribute__ ((__unused__)),
  	       UWtype a0 __attribute__ ((__unused__)),
*************** const UQItype __clz_tab[] =
*** 503,509 ****
       defined (L_umoddi3) || defined (L_moddi3))
  static inline
  #endif
! UDWtype
  __udivmoddi4 (UDWtype n, UDWtype d, UDWtype *rp)
  {
    DWunion ww;
--- 503,509 ----
       defined (L_umoddi3) || defined (L_moddi3))
  static inline
  #endif
! UDWtype __attribute__ ((__no_profile__))
  __udivmoddi4 (UDWtype n, UDWtype d, UDWtype *rp)
  {
    DWunion ww;
*************** __udivmoddi4 (UDWtype n, UDWtype d, UDWt
*** 722,728 ****
  #endif
  
  #ifdef L_divdi3
! DWtype
  __divdi3 (DWtype u, DWtype v)
  {
    word_type c = 0;
--- 722,728 ----
  #endif
  
  #ifdef L_divdi3
! DWtype __attribute__ ((__no_profile__))
  __divdi3 (DWtype u, DWtype v)
  {
    word_type c = 0;
*************** __divdi3 (DWtype u, DWtype v)
*** 748,754 ****
  #endif
  
  #ifdef L_moddi3
! DWtype
  __moddi3 (DWtype u, DWtype v)
  {
    word_type c = 0;
--- 748,754 ----
  #endif
  
  #ifdef L_moddi3
! DWtype __attribute__ ((__no_profile__))
  __moddi3 (DWtype u, DWtype v)
  {
    word_type c = 0;
*************** __moddi3 (DWtype u, DWtype v)
*** 773,779 ****
  #endif
  
  #ifdef L_umoddi3
! UDWtype
  __umoddi3 (UDWtype u, UDWtype v)
  {
    UDWtype w;
--- 773,779 ----
  #endif
  
  #ifdef L_umoddi3
! UDWtype __attribute__ ((__no_profile__))
  __umoddi3 (UDWtype u, UDWtype v)
  {
    UDWtype w;
*************** __umoddi3 (UDWtype u, UDWtype v)
*** 785,791 ****
  #endif
  
  #ifdef L_udivdi3
! UDWtype
  __udivdi3 (UDWtype n, UDWtype d)
  {
    return __udivmoddi4 (n, d, (UDWtype *) 0);
--- 785,791 ----
  #endif
  
  #ifdef L_udivdi3
! UDWtype __attribute__ ((__no_profile__))
  __udivdi3 (UDWtype n, UDWtype d)
  {
    return __udivmoddi4 (n, d, (UDWtype *) 0);
*************** __udivdi3 (UDWtype n, UDWtype d)
*** 793,799 ****
  #endif
  
  #ifdef L_cmpdi2
! word_type
  __cmpdi2 (DWtype a, DWtype b)
  {
    DWunion au, bu;
--- 793,799 ----
  #endif
  
  #ifdef L_cmpdi2
! word_type __attribute__ ((__no_profile__))
  __cmpdi2 (DWtype a, DWtype b)
  {
    DWunion au, bu;
*************** __cmpdi2 (DWtype a, DWtype b)
*** 813,819 ****
  #endif
  
  #ifdef L_ucmpdi2
! word_type
  __ucmpdi2 (DWtype a, DWtype b)
  {
    DWunion au, bu;
--- 813,819 ----
  #endif
  
  #ifdef L_ucmpdi2
! word_type __attribute__ ((__no_profile__))
  __ucmpdi2 (DWtype a, DWtype b)
  {
    DWunion au, bu;
*************** __ucmpdi2 (DWtype a, DWtype b)
*** 836,842 ****
  #define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
  #define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
  
! DWtype
  __fixunstfDI (TFtype a)
  {
    TFtype b;
--- 836,842 ----
  #define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
  #define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
  
! DWtype __attribute__ ((__no_profile__))
  __fixunstfDI (TFtype a)
  {
    TFtype b;
*************** __fixunstfDI (TFtype a)
*** 865,871 ****
  #endif
  
  #if defined(L_fixtfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128)
! DWtype
  __fixtfdi (TFtype a)
  {
    if (a < 0)
--- 865,871 ----
  #endif
  
  #if defined(L_fixtfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128)
! DWtype __attribute__ ((__no_profile__))
  __fixtfdi (TFtype a)
  {
    if (a < 0)
*************** __fixtfdi (TFtype a)
*** 878,884 ****
  #define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
  #define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
  
! DWtype
  __fixunsxfDI (XFtype a)
  {
    XFtype b;
--- 878,884 ----
  #define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
  #define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
  
! DWtype __attribute__ ((__no_profile__))
  __fixunsxfDI (XFtype a)
  {
    XFtype b;
*************** __fixunsxfDI (XFtype a)
*** 907,913 ****
  #endif
  
  #if defined(L_fixxfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96)
! DWtype
  __fixxfdi (XFtype a)
  {
    if (a < 0)
--- 907,913 ----
  #endif
  
  #if defined(L_fixxfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96)
! DWtype __attribute__ ((__no_profile__))
  __fixxfdi (XFtype a)
  {
    if (a < 0)
*************** __fixxfdi (XFtype a)
*** 920,926 ****
  #define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
  #define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
  
! DWtype
  __fixunsdfDI (DFtype a)
  {
    DFtype b;
--- 920,926 ----
  #define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
  #define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
  
! DWtype __attribute__ ((__no_profile__))
  __fixunsdfDI (DFtype a)
  {
    DFtype b;
*************** __fixunsdfDI (DFtype a)
*** 949,955 ****
  #endif
  
  #ifdef L_fixdfdi
! DWtype
  __fixdfdi (DFtype a)
  {
    if (a < 0)
--- 949,955 ----
  #endif
  
  #ifdef L_fixdfdi
! DWtype __attribute__ ((__no_profile__))
  __fixdfdi (DFtype a)
  {
    if (a < 0)
*************** __fixdfdi (DFtype a)
*** 962,968 ****
  #define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
  #define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
  
! DWtype
  __fixunssfDI (SFtype original_a)
  {
    /* Convert the SFtype to a DFtype, because that is surely not going
--- 962,968 ----
  #define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
  #define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
  
! DWtype __attribute__ ((__no_profile__))
  __fixunssfDI (SFtype original_a)
  {
    /* Convert the SFtype to a DFtype, because that is surely not going
*************** __fixunssfDI (SFtype original_a)
*** 995,1001 ****
  #endif
  
  #ifdef L_fixsfdi
! DWtype
  __fixsfdi (SFtype a)
  {
    if (a < 0)
--- 995,1001 ----
  #endif
  
  #ifdef L_fixsfdi
! DWtype __attribute__ ((__no_profile__))
  __fixsfdi (SFtype a)
  {
    if (a < 0)
*************** __fixsfdi (SFtype a)
*** 1009,1015 ****
  #define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2))
  #define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
  
! XFtype
  __floatdixf (DWtype u)
  {
    XFtype d;
--- 1009,1015 ----
  #define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2))
  #define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
  
! XFtype __attribute__ ((__no_profile__))
  __floatdixf (DWtype u)
  {
    XFtype d;
*************** __floatdixf (DWtype u)
*** 1028,1034 ****
  #define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2))
  #define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
  
! TFtype
  __floatditf (DWtype u)
  {
    TFtype d;
--- 1028,1034 ----
  #define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2))
  #define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
  
! TFtype __attribute__ ((__no_profile__))
  __floatditf (DWtype u)
  {
    TFtype d;
*************** __floatditf (DWtype u)
*** 1047,1053 ****
  #define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2))
  #define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
  
! DFtype
  __floatdidf (DWtype u)
  {
    DFtype d;
--- 1047,1053 ----
  #define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2))
  #define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
  
! DFtype __attribute__ ((__no_profile__))
  __floatdidf (DWtype u)
  {
    DFtype d;
*************** __floatdidf (DWtype u)
*** 1095,1101 ****
  #define SF_SIZE 24
  #endif
  
! SFtype
  __floatdisf (DWtype u)
  {
    /* Do the calculation in DFmode
--- 1095,1101 ----
  #define SF_SIZE 24
  #endif
  
! SFtype __attribute__ ((__no_profile__))
  __floatdisf (DWtype u)
  {
    /* Do the calculation in DFmode
*************** __floatdisf (DWtype u)
*** 1142,1148 ****
  #undef MAX
  #include <limits.h>
  
! UWtype
  __fixunsxfSI (XFtype a)
  {
    if (a >= - (DFtype) Wtype_MIN)
--- 1142,1148 ----
  #undef MAX
  #include <limits.h>
  
! UWtype __attribute__ ((__no_profile__))
  __fixunsxfSI (XFtype a)
  {
    if (a >= - (DFtype) Wtype_MIN)
*************** __fixunsxfSI (XFtype a)
*** 1164,1170 ****
  #undef MAX
  #include <limits.h>
  
! UWtype
  __fixunsdfSI (DFtype a)
  {
    if (a >= - (DFtype) Wtype_MIN)
--- 1164,1170 ----
  #undef MAX
  #include <limits.h>
  
! UWtype __attribute__ ((__no_profile__))
  __fixunsdfSI (DFtype a)
  {
    if (a >= - (DFtype) Wtype_MIN)
*************** __fixunsdfSI (DFtype a)
*** 1186,1192 ****
  #undef MAX
  #include <limits.h>
  
! UWtype
  __fixunssfSI (SFtype a)
  {
    if (a >= - (SFtype) Wtype_MIN)
--- 1186,1192 ----
  #undef MAX
  #include <limits.h>
  
! UWtype __attribute__ ((__no_profile__))
  __fixunssfSI (SFtype a)
  {
    if (a >= - (SFtype) Wtype_MIN)
*************** __eprintf (const char *string, const cha
*** 1263,1275 ****
  
  #ifdef L_bb
  
- #if LONG_TYPE_SIZE == GCOV_TYPE_SIZE
- typedef long gcov_type;
- #else
- typedef long long gcov_type;
- #endif
- 
- 
  struct bb_function_info {
    long checksum;
    int arc_count;
--- 1263,1268 ----
*************** BLOCK_PROFILER_CODE
*** 1310,1318 ****
  #include <errno.h>
  #endif
  
  static struct bb *bb_head;
  
! void
  __bb_exit_func (void)
  {
    FILE *da_file;
--- 1303,1357 ----
  #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 __attribute__ ((__no_profile__))
  __bb_exit_func (void)
  {
    FILE *da_file;
*************** __bb_exit_func (void)
*** 1342,1347 ****
--- 1381,1420 ----
  	}
      }
  
+ #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)
      {
*************** __bb_exit_func (void)
*** 1470,1503 ****
  	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;
--- 1543,1671 ----
  	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 * __attribute__ ((__no_profile__))
+ __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 * __attribute__ ((__no_profile__))
+ __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 __attribute__ ((__no_profile__))
+ __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 * __attribute__ ((__no_profile__))
! __bb_thread_start_func (void)
! {
!   return (void *) 0;
! }
! 
! #endif
! 
! void __attribute__ ((__no_profile__))
! __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 __attribute__ ((__no_profile__))
  __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	2001/08/22 14:35:22	1.20
--- libgcc2.h	2002/01/03 20:42:50
*************** extern void __eprintf (const char *, con
*** 28,43 ****
    __attribute__ ((__noreturn__));
  
  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 *);
! extern short int __get_eh_table_version (struct exception_descriptor *);
  
  /* Permit the tm.h file to select the endianness to use just for this
     file.  This is used when the endianness is determined when the
--- 28,53 ----
    __attribute__ ((__noreturn__));
  
  struct bb;
! extern void __bb_exit_func (void) __attribute__ ((__no_profile__));
! extern void __bb_init_func (struct bb *, int *) __attribute__ ((__no_profile__));
! extern void *__bb_thread_start_func (void) __attribute__ ((__no_profile__));
! extern void __bb_thread_end_func (void *) __attribute__ ((__no_profile__));
! extern void __bb_fork_func (void) __attribute__ ((__no_profile__));
! extern void __bb_trace_func (void) __attribute__ ((__no_profile__));
! extern void __bb_trace_ret (void) __attribute__ ((__no_profile__));
! extern void __bb_init_trace_func (struct bb *, unsigned long) __attribute__ ((__no_profile__));
  
+ #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) __attribute__ ((__no_profile__));
+ 
  struct exception_descriptor;
! extern short int __get_eh_table_language (struct exception_descriptor *) __attribute__ ((__no_profile__));
! extern short int __get_eh_table_version (struct exception_descriptor *) __attribute__ ((__no_profile__));
  
  /* Permit the tm.h file to select the endianness to use just for this
     file.  This is used when the endianness is determined when the
*************** typedef int word_type __attribute__ ((mo
*** 211,279 ****
  #define __fixunsdfSI	__NW(fixunsdf,)
  #define __fixunssfSI	__NW(fixunssf,)
  
! extern DWtype __muldi3 (DWtype, DWtype);
! extern DWtype __divdi3 (DWtype, DWtype);
! extern UDWtype __udivdi3 (UDWtype, UDWtype);
! extern UDWtype __umoddi3 (UDWtype, UDWtype);
! extern DWtype __moddi3 (DWtype, DWtype);
  
  /* __udivmoddi4 is static inline when building other libgcc2 portions.  */
  #if (!defined (L_udivdi3) && !defined (L_divdi3) && \
       !defined (L_umoddi3) && !defined (L_moddi3))
! extern UDWtype __udivmoddi4 (UDWtype, UDWtype, UDWtype *);
  #endif
  
  /* __negdi2 is static inline when building other libgcc2 portions.  */
  #if !defined(L_divdi3) && !defined(L_moddi3)
! extern DWtype __negdi2 (DWtype);
  #endif
  
! extern DWtype __lshrdi3 (DWtype, word_type);
! extern DWtype __ashldi3 (DWtype, word_type);
! extern DWtype __ashrdi3 (DWtype, word_type);
! extern DWtype __ffsdi2 (DWtype);
  
  /* __udiv_w_sdiv is static inline when building other libgcc2 portions.  */
  #if (!defined(L_udivdi3) && !defined(L_divdi3) && \
       !defined(L_umoddi3) && !defined(L_moddi3))
! extern UWtype __udiv_w_sdiv (UWtype *, UWtype, UWtype, UWtype);
  #endif
  
! extern word_type __cmpdi2 (DWtype, DWtype);
! extern word_type __ucmpdi2 (DWtype, DWtype);
  
! extern Wtype __absvsi2 (Wtype);
! extern DWtype __absvdi2 (DWtype);
! extern Wtype __addvsi3 (Wtype, Wtype);
! extern DWtype __addvdi3 (DWtype, DWtype);
! extern Wtype __subvsi3 (Wtype, Wtype);
! extern DWtype __subvdi3 (DWtype, DWtype);
! extern Wtype __mulvsi3 (Wtype, Wtype);
! extern DWtype __mulvdi3 (DWtype, DWtype);
! extern Wtype __negvsi2 (Wtype);
! extern DWtype __negvdi2 (DWtype);
  
  #if BITS_PER_UNIT == 8
! extern DWtype __fixdfdi (DFtype);
! extern DWtype __fixsfdi (SFtype);
! extern DFtype __floatdidf (DWtype);
! extern SFtype __floatdisf (DWtype);
! extern UWtype __fixunsdfSI (DFtype);
! extern UWtype __fixunssfSI (SFtype);
! extern DWtype __fixunsdfDI (DFtype);
! extern DWtype __fixunssfDI (SFtype);
  
  #if LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96
! extern DWtype __fixxfdi (XFtype);
! extern DWtype __fixunsxfDI (XFtype);
! extern XFtype __floatdixf (DWtype);
! extern UWtype __fixunsxfSI (XFtype);
  #endif
  
  #if LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128
! extern DWtype __fixunstfDI (TFtype);
! extern DWtype __fixtfdi (TFtype);
! extern TFtype __floatditf (DWtype);
  #endif
  #endif /* BITS_PER_UNIT == 8 */
  
--- 221,289 ----
  #define __fixunsdfSI	__NW(fixunsdf,)
  #define __fixunssfSI	__NW(fixunssf,)
  
! extern DWtype __muldi3 (DWtype, DWtype) __attribute__ ((__no_profile__));
! extern DWtype __divdi3 (DWtype, DWtype) __attribute__ ((__no_profile__));
! extern UDWtype __udivdi3 (UDWtype, UDWtype) __attribute__ ((__no_profile__));
! extern UDWtype __umoddi3 (UDWtype, UDWtype) __attribute__ ((__no_profile__));
! extern DWtype __moddi3 (DWtype, DWtype) __attribute__ ((__no_profile__));
  
  /* __udivmoddi4 is static inline when building other libgcc2 portions.  */
  #if (!defined (L_udivdi3) && !defined (L_divdi3) && \
       !defined (L_umoddi3) && !defined (L_moddi3))
! extern UDWtype __udivmoddi4 (UDWtype, UDWtype, UDWtype *) __attribute__ ((__no_profile__));
  #endif
  
  /* __negdi2 is static inline when building other libgcc2 portions.  */
  #if !defined(L_divdi3) && !defined(L_moddi3)
! extern DWtype __negdi2 (DWtype) __attribute__ ((__no_profile__));
  #endif
  
! extern DWtype __lshrdi3 (DWtype, word_type) __attribute__ ((__no_profile__));
! extern DWtype __ashldi3 (DWtype, word_type) __attribute__ ((__no_profile__));
! extern DWtype __ashrdi3 (DWtype, word_type) __attribute__ ((__no_profile__));
! extern DWtype __ffsdi2 (DWtype) __attribute__ ((__no_profile__));
  
  /* __udiv_w_sdiv is static inline when building other libgcc2 portions.  */
  #if (!defined(L_udivdi3) && !defined(L_divdi3) && \
       !defined(L_umoddi3) && !defined(L_moddi3))
! extern UWtype __udiv_w_sdiv (UWtype *, UWtype, UWtype, UWtype) __attribute__ ((__no_profile__));
  #endif
  
! extern word_type __cmpdi2 (DWtype, DWtype) __attribute__ ((__no_profile__));
! extern word_type __ucmpdi2 (DWtype, DWtype) __attribute__ ((__no_profile__));
  
! extern Wtype __absvsi2 (Wtype) __attribute__ ((__no_profile__));
! extern DWtype __absvdi2 (DWtype) __attribute__ ((__no_profile__));
! extern Wtype __addvsi3 (Wtype, Wtype) __attribute__ ((__no_profile__));
! extern DWtype __addvdi3 (DWtype, DWtype) __attribute__ ((__no_profile__));
! extern Wtype __subvsi3 (Wtype, Wtype) __attribute__ ((__no_profile__));
! extern DWtype __subvdi3 (DWtype, DWtype) __attribute__ ((__no_profile__));
! extern Wtype __mulvsi3 (Wtype, Wtype) __attribute__ ((__no_profile__));
! extern DWtype __mulvdi3 (DWtype, DWtype) __attribute__ ((__no_profile__));
! extern Wtype __negvsi2 (Wtype) __attribute__ ((__no_profile__));
! extern DWtype __negvdi2 (DWtype) __attribute__ ((__no_profile__));
  
  #if BITS_PER_UNIT == 8
! extern DWtype __fixdfdi (DFtype) __attribute__ ((__no_profile__));
! extern DWtype __fixsfdi (SFtype) __attribute__ ((__no_profile__));
! extern DFtype __floatdidf (DWtype) __attribute__ ((__no_profile__));
! extern SFtype __floatdisf (DWtype) __attribute__ ((__no_profile__));
! extern UWtype __fixunsdfSI (DFtype) __attribute__ ((__no_profile__));
! extern UWtype __fixunssfSI (SFtype) __attribute__ ((__no_profile__));
! extern DWtype __fixunsdfDI (DFtype) __attribute__ ((__no_profile__));
! extern DWtype __fixunssfDI (SFtype) __attribute__ ((__no_profile__));
  
  #if LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96
! extern DWtype __fixxfdi (XFtype) __attribute__ ((__no_profile__));
! extern DWtype __fixunsxfDI (XFtype) __attribute__ ((__no_profile__));
! extern XFtype __floatdixf (DWtype) __attribute__ ((__no_profile__));
! extern UWtype __fixunsxfSI (XFtype) __attribute__ ((__no_profile__));
  #endif
  
  #if LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128
! extern DWtype __fixunstfDI (TFtype) __attribute__ ((__no_profile__));
! extern DWtype __fixtfdi (TFtype) __attribute__ ((__no_profile__));
! extern TFtype __floatditf (DWtype) __attribute__ ((__no_profile__));
  #endif
  #endif /* BITS_PER_UNIT == 8 */
  
Index: optabs.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/optabs.c,v
retrieving revision 1.116.2.2
diff -c -3 -p -r1.116.2.2 optabs.c
*** optabs.c	2001/12/14 23:08:20	1.116.2.2
--- optabs.c	2002/01/03 20:42:52
*************** init_optabs ()
*** 5056,5061 ****
--- 5056,5065 ----
    profile_function_exit_libfunc
      = init_one_libfunc ("__cyg_profile_func_exit");
  
+   /* For thread-safe arc profiling.  */
+   find_arc_counters_libfunc
+     = init_one_libfunc ("__bb_find_arc_counters");
+ 
  #ifdef HAVE_conditional_trap
    init_traps ();
  #endif
Index: profile.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/profile.c,v
retrieving revision 1.76.2.4
diff -c -3 -p -r1.76.2.4 profile.c
*** profile.c	2002/01/01 20:26:18	1.76.2.4
--- profile.c	2002/01/03 20:42:53
*************** Software Foundation, 59 Temple Place - S
*** 50,55 ****
--- 50,57 ----
  #include "gcov-io.h"
  #include "target.h"
  #include "profile.h"
+ #include "libfuncs.h"
+ #include "gthr.h"
  
  /* Additional information about the edges we need.  */
  struct edge_info
*************** static gcov_type * get_exec_counts PARAM
*** 117,127 ****
--- 119,207 ----
  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)
*** 145,150 ****
--- 225,232 ----
  	  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)
*** 152,160 ****
  			 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;
  	}
--- 234,243 ----
  			 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;
  	}
*************** instrument_edges (el)
*** 168,174 ****
    if (rtl_dump_file)
      fprintf (rtl_dump_file, "%d edges instrumented\n", num_instr_edges);
  
!   commit_edge_insertions ();
  }
  
  /* Output STRING to bb_file, surrounded by DELIMITER.  */
--- 251,257 ----
    if (rtl_dump_file)
      fprintf (rtl_dump_file, "%d edges instrumented\n", num_instr_edges);
  
!   commit_edge_insertions_watch_calls ();
  }
  
  /* Output STRING to bb_file, surrounded by DELIMITER.  */
*************** branch_prob ()
*** 718,724 ****
    int i;
    int num_edges, ignored_edges;
    struct edge_list *el;
!   
    profile_info.current_function_cfg_checksum = compute_checksum ();
  
    if (rtl_dump_file)
--- 801,807 ----
    int i;
    int num_edges, ignored_edges;
    struct edge_list *el;
! 
    profile_info.current_function_cfg_checksum = compute_checksum ();
  
    if (rtl_dump_file)
*************** branch_prob ()
*** 997,1002 ****
--- 1080,1091 ----
  
    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)
*** 1072,1085 ****
    /* 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);
  	}
--- 1161,1181 ----
    /* 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)
*** 1093,1098 ****
--- 1189,1197 ----
  	  && !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)
*** 1105,1110 ****
--- 1204,1212 ----
        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);
  	}
*************** end_branch_prob ()
*** 1193,1203 ****
        fclose (bbg_file);
      }
  
!   if (flag_branch_probabilities)
!     {
!       if (da_file)
! 	fclose (da_file);
!     }
  
    if (rtl_dump_file)
      {
--- 1295,1302 ----
        fclose (bbg_file);
      }
  
!   if (flag_branch_probabilities && da_file)
!     fclose (da_file);
  
    if (rtl_dump_file)
      {
*************** gen_edge_profiler (edgeno)
*** 1260,1270 ****
    rtx sequence;
  
    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);
  
--- 1359,1377 ----
    rtx sequence;
  
    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 ()
*** 1284,1297 ****
  {
    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.  */
--- 1391,1401 ----
  {
    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 ()
*** 1334,1346 ****
    init_function_start (fndecl, input_filename, lineno);
    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);
    poplevel (1, 0, 1);
--- 1438,1463 ----
    init_function_start (fndecl, input_filename, lineno);
    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);
    poplevel (1, 0, 1);
*************** output_func_start_profiler ()
*** 1350,1369 ****
       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);
--- 1467,1476 ----
Index: toplev.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/toplev.c,v
retrieving revision 1.537.2.22
diff -c -3 -p -r1.537.2.22 toplev.c
*** toplev.c	2002/01/03 14:25:12	1.537.2.22
--- toplev.c	2002/01/03 20:42:55
*************** rest_of_compilation (decl)
*** 2966,2972 ****
  
       life_analyzis rarely eliminates modification of external memory.  */
    mark_constant_function ();
!   if (profile_arc_flag || flag_test_coverage || flag_branch_probabilities)
      branch_prob ();
  
    if (optimize)
--- 2966,2973 ----
  
       life_analyzis rarely eliminates modification of external memory.  */
    mark_constant_function ();
!   if ((profile_arc_flag || flag_test_coverage || flag_branch_probabilities)
!       && !cfun->no_profile)
      branch_prob ();
  
    if (optimize)
Index: tracer.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/Attic/tracer.c,v
retrieving revision 1.1.2.16
diff -c -3 -p -r1.1.2.16 tracer.c
*** tracer.c	2001/12/31 14:40:31	1.1.2.16
--- tracer.c	2002/01/03 20:42:55
*************** static bool ignore_bb_p			PARAMS ((basic
*** 85,91 ****
     wastefull and overactive tracing of badly predictable jumps interfere
     badly with if converison pass.  The thresholds needs to be different.  */
  
! #define MIN_BRANCH_PROBABILITY (flag_branch_probabilities ? 0.8 : 0.7)
  
  /* Return true if BB has been seen - it is connected to some trace
     already.  */
--- 85,91 ----
     wastefull and overactive tracing of badly predictable jumps interfere
     badly with if converison pass.  The thresholds needs to be different.  */
  
! #define MIN_BRANCH_PROBABILITY (flag_branch_probabilities ? 0.8 : 0.5)
  
  /* Return true if BB has been seen - it is connected to some trace
     already.  */
*************** find_best_successor (basic_block bb)
*** 149,155 ****
        best = e;
    if (!best || ignore_bb_p (best->dest))
      return NULL;
!   if (best->probability < (int)(REG_BR_PROB_BASE * MIN_BRANCH_PROBABILITY))
      return NULL;
    return best;
  }
--- 149,155 ----
        best = e;
    if (!best || ignore_bb_p (best->dest))
      return NULL;
!   if (best->probability <= (int)(REG_BR_PROB_BASE * MIN_BRANCH_PROBABILITY))
      return NULL;
    return best;
  }


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