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]

[tree-profiling] coverage code for trees


Hi,
this patch implements coveraging on trees.  It fixes all the gcov
failures we have but one.  The problem in last remaining is that cleanup
expansion produce destructor call on the end of block and attach it
locus of the first line of the block so the first line appears to be
executed twice.  Not sure how to avoid gimplifier from doing it.
Except for that the probabilities now looks more consistent and there is
less noise.  I also noticed two bugs in the testcases.

Bootstrapped & regtested on tree-profilng branch and installed.
I am not sure what is the plan to deal with gcov failures on tree-ssa,
but it may be wortwhile to think about backporting it.  It however needs
CFG to be built at -O0 -fprofile-arcs.

Honza

Index: ChangeLog.profiling
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/ChangeLog.profiling,v
retrieving revision 1.1.2.15
diff -c -3 -p -r1.1.2.15 ChangeLog.profiling
*** ChangeLog.profiling	15 Mar 2004 16:46:36 -0000	1.1.2.15
--- ChangeLog.profiling	15 Mar 2004 16:54:22 -0000
***************
*** 1,5 ****
--- 1,23 ----
  2004-03-15  Jan Hubicka  <jh@suse.cz>
  
+ 	* gimple-low.c (lower_cond_expr):  Do not re-use explicit gotos.
+ 	* profile.c (branch_prob): Do not verify flow info; re-invent fallthru
+ 	flags on trees; output coverage info for trees.
+ 	* toplev.c (flag_tree_based_profiling): Enable it by default.
+ 	(process_options): Do not sorry about coverage on trees.
+ 	* tree-cfg.c (make_edges): Only delete unreachable block or mess the
+ 	coverage info.
+ 	(make_goto_expr_edges): Preserve locators for elliminated explicit
+ 	gotos.
+ 	(tree_find_edge_insert_loc): Deal with inserting just before return
+ 	statement.
+ 	* tree-optimize.c (init_tree_optimization_passes): Make tree-profilng
+ 	to be run even when not optimizing.
+ 	* tree-profile.c (do_tree_profiling): Don't run profilng when we are
+ 	not profilng.
+ 
+ 2004-03-15  Jan Hubicka  <jh@suse.cz>
+ 
  	* cfgrtl.c (rtl_create_basic_block): Pre-allocate basic_block_info
  	array.
  
Index: gimple-low.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/gimple-low.c,v
retrieving revision 1.1.4.17.2.5
diff -c -3 -p -r1.1.4.17.2.5 gimple-low.c
*** gimple-low.c	7 Mar 2004 22:23:54 -0000	1.1.4.17.2.5
--- gimple-low.c	15 Mar 2004 16:54:24 -0000
*************** lower_cond_expr (tree_stmt_iterator *tsi
*** 290,299 ****
    lower_stmt_body (else_branch, data);
  
    then_goto = expr_only (then_branch);
!   then_is_goto = then_goto && simple_goto_p (then_goto);
  
    else_goto = expr_only (else_branch);
!   else_is_goto = else_goto && simple_goto_p (else_goto);
  
    if (!then_is_goto || !else_is_goto)
      {
--- 290,301 ----
    lower_stmt_body (else_branch, data);
  
    then_goto = expr_only (then_branch);
!   then_is_goto = (then_goto && simple_goto_p (then_goto)
! 		  && !EXPR_LOCUS (then_goto));
  
    else_goto = expr_only (else_branch);
!   else_is_goto = (else_goto && simple_goto_p (else_goto)
! 		  && !EXPR_LOCUS (else_goto));
  
    if (!then_is_goto || !else_is_goto)
      {
Index: profile.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/profile.c,v
retrieving revision 1.93.2.25.2.3
diff -c -3 -p -r1.93.2.25.2.3 profile.c
*** profile.c	7 Mar 2004 22:23:54 -0000	1.93.2.25.2.3
--- profile.c	15 Mar 2004 16:54:24 -0000
*************** branch_prob (void)
*** 786,795 ****
  	}
      }
  
- #ifdef ENABLE_CHECKING
-   verify_flow_info ();
- #endif
- 
    /* Create spanning tree from basic block graph, mark each edge that is
       on the spanning tree.  We insert as many abnormal and critical edges
       as possible to minimize number of edge splits necessary.  */
--- 786,791 ----
*************** branch_prob (void)
*** 872,877 ****
--- 868,879 ----
  		    flag_bits |= GCOV_ARC_FAKE;
  		  if (e->flags & EDGE_FALLTHRU)
  		    flag_bits |= GCOV_ARC_FALLTHROUGH;
+ 		  /* On trees we don't have fallthru flags, but we can
+ 		     recompute them from CFG shape.  */
+ 		  if (ir_type ()
+ 		      && e->flags & (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE)
+ 		      && e->src->next_bb == e->dest)
+ 		    flag_bits |= GCOV_ARC_FALLTHROUGH;
  
  		  gcov_write_unsigned (BB_TO_GCOV_INDEX (e->dest));
  		  gcov_write_unsigned (flag_bits);
*************** branch_prob (void)
*** 883,927 ****
      }
  
    /* Line numbers.  */
!   /* FIXME:  make this work for trees.  (Line numbers are in location_t
!      objects, but aren't always attached to the obvious tree...) */
!   if (coverage_begin_output () && !ir_type ())
      {
!       char const *prev_file_name = NULL;
!       gcov_position_t offset;
! 
!       FOR_EACH_BB (bb)
  	{
! 	  rtx insn = BB_HEAD (bb);
! 	  int ignore_next_note = 0;
  
! 	  offset = 0;
  
! 	  /* We are looking for line number notes.  Search backward
! 	     before basic block to find correct ones.  */
! 	  insn = prev_nonnote_insn (insn);
! 	  if (!insn)
! 	    insn = get_insns ();
! 	  else
! 	    insn = NEXT_INSN (insn);
  
! 	  while (insn != BB_END (bb))
  	    {
! 	      if (GET_CODE (insn) == NOTE)
  		{
! 		  /* Must ignore the line number notes that
! 		     immediately follow the end of an inline function
! 		     to avoid counting it twice.  There is a note
! 		     before the call, and one after the call.  */
! 		  if (NOTE_LINE_NUMBER (insn)
! 		      == NOTE_INSN_REPEATED_LINE_NUMBER)
! 		    ignore_next_note = 1;
! 		  else if (NOTE_LINE_NUMBER (insn) <= 0)
! 		    /*NOP*/;
! 		  else if (ignore_next_note)
! 		    ignore_next_note = 0;
! 		  else
  		    {
  		      if (!offset)
  			{
  			  offset = gcov_write_tag (GCOV_TAG_LINES);
--- 885,997 ----
      }
  
    /* Line numbers.  */
!   if (coverage_begin_output ())
      {
!       if (!ir_type ())
  	{
! 	  char const *prev_file_name = NULL;
! 	  gcov_position_t offset;
  
! 	  FOR_EACH_BB (bb)
! 	    {
! 	      rtx insn = BB_HEAD (bb);
! 	      int ignore_next_note = 0;
! 
! 	      offset = 0;
  
! 	      /* We are looking for line number notes.  Search backward
! 		 before basic block to find correct ones.  */
! 	      insn = prev_nonnote_insn (insn);
! 	      if (!insn)
! 		insn = get_insns ();
! 	      else
! 		insn = NEXT_INSN (insn);
! 
! 	      while (insn != BB_END (bb))
! 		{
! 		  if (GET_CODE (insn) == NOTE)
! 		    {
! 		      /* Must ignore the line number notes that
! 			 immediately follow the end of an inline function
! 			 to avoid counting it twice.  There is a note
! 			 before the call, and one after the call.  */
! 		      if (NOTE_LINE_NUMBER (insn)
! 			  == NOTE_INSN_REPEATED_LINE_NUMBER)
! 			ignore_next_note = 1;
! 		      else if (NOTE_LINE_NUMBER (insn) <= 0)
! 			/*NOP*/;
! 		      else if (ignore_next_note)
! 			ignore_next_note = 0;
! 		      else
! 			{
! 			  if (!offset)
! 			    {
! 			      offset = gcov_write_tag (GCOV_TAG_LINES);
! 			      gcov_write_unsigned (BB_TO_GCOV_INDEX (bb));
! 			    }
! 
! 			  /* If this is a new source file, then output the
! 			     file's name to the .bb file.  */
! 			  if (!prev_file_name
! 			      || strcmp (NOTE_SOURCE_FILE (insn),
! 					 prev_file_name))
! 			    {
! 			      prev_file_name = NOTE_SOURCE_FILE (insn);
! 			      gcov_write_unsigned (0);
! 			      gcov_write_string (prev_file_name);
! 			    }
! 			  gcov_write_unsigned (NOTE_LINE_NUMBER (insn));
! 			}
! 		    }
! 		  insn = NEXT_INSN (insn);
! 		}
! 
! 	      if (offset)
! 		{
! 		  /* A file of NULL indicates the end of run.  */
! 		  gcov_write_unsigned (0);
! 		  gcov_write_string (NULL);
! 		  gcov_write_length (offset);
! 		}
! 	    }
! 	}
!       else
! 	{
! 	  char const *prev_file_name = NULL;
! 	  gcov_position_t offset;
! 	  location_t *curr_location = NULL;
  
! 	  FOR_EACH_BB (bb)
  	    {
! 	      block_stmt_iterator bsi;
! 
! 	      offset = 0;
! 
! 	      if (bb == ENTRY_BLOCK_PTR->next_bb)
  		{
! 		  curr_location = &DECL_SOURCE_LOCATION (current_function_decl);
! 		  if (!offset)
  		    {
+ 		      offset = gcov_write_tag (GCOV_TAG_LINES);
+ 		      gcov_write_unsigned (BB_TO_GCOV_INDEX (bb));
+ 		    }
+ 
+ 		  /* If this is a new source file, then output the
+ 		     file's name to the .bb file.  */
+ 		  prev_file_name = curr_location->file;
+ 		  gcov_write_unsigned (0);
+ 		  gcov_write_string (prev_file_name);
+ 		  gcov_write_unsigned (curr_location->line);
+ 		}
+ 
+ 	      for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+ 		{
+ 		  tree stmt = bsi_stmt (bsi);
+ 		  if (EXPR_LOCUS (stmt)
+ 		      && (EXPR_LOCUS (stmt)->line != curr_location->line
+ 		          || strcmp (EXPR_LOCUS (stmt)->file, curr_location->file)))
+ 		    {
+ 		      curr_location = EXPR_LOCUS (stmt);
  		      if (!offset)
  			{
  			  offset = gcov_write_tag (GCOV_TAG_LINES);
*************** branch_prob (void)
*** 930,957 ****
  
  		      /* If this is a new source file, then output the
  			 file's name to the .bb file.  */
! 		      if (!prev_file_name
! 			  || strcmp (NOTE_SOURCE_FILE (insn),
! 				     prev_file_name))
  			{
! 			  prev_file_name = NOTE_SOURCE_FILE (insn);
  			  gcov_write_unsigned (0);
  			  gcov_write_string (prev_file_name);
  			}
! 		      gcov_write_unsigned (NOTE_LINE_NUMBER (insn));
  		    }
  		}
- 	      insn = NEXT_INSN (insn);
- 	    }
  
! 	  if (offset)
! 	    {
! 	      /* A file of NULL indicates the end of run.  */
! 	      gcov_write_unsigned (0);
! 	      gcov_write_string (NULL);
! 	      gcov_write_length (offset);
  	    }
! 	}
      }
  
    ENTRY_BLOCK_PTR->index = ENTRY_BLOCK;
--- 1000,1024 ----
  
  		      /* If this is a new source file, then output the
  			 file's name to the .bb file.  */
! 		      if (strcmp (curr_location->file, prev_file_name))
  			{
! 			  prev_file_name = curr_location->file;
  			  gcov_write_unsigned (0);
  			  gcov_write_string (prev_file_name);
  			}
! 		      gcov_write_unsigned (curr_location->line);
  		    }
  		}
  
! 	      if (offset)
! 		{
! 		  /* A file of NULL indicates the end of run.  */
! 		  gcov_write_unsigned (0);
! 		  gcov_write_string (NULL);
! 		  gcov_write_length (offset);
! 		}
  	    }
! 	 }
      }
  
    ENTRY_BLOCK_PTR->index = ENTRY_BLOCK;
Index: toplev.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/toplev.c,v
retrieving revision 1.654.2.97.2.5
diff -c -3 -p -r1.654.2.97.2.5 toplev.c
*** toplev.c	7 Mar 2004 22:23:55 -0000	1.654.2.97.2.5
--- toplev.c	15 Mar 2004 16:54:24 -0000
*************** int flag_renumber_insns = 1;
*** 788,794 ****
  int flag_new_regalloc = 0;
  
  /* If nonzero, use tree-based instead of rtl-based profiling.  */
! int flag_tree_based_profiling = 0;
  
  /* Enable SSA-GVN on trees.  */
  int flag_tree_gvn = 0;
--- 788,794 ----
  int flag_new_regalloc = 0;
  
  /* If nonzero, use tree-based instead of rtl-based profiling.  */
! int flag_tree_based_profiling = 1;
  
  /* Enable SSA-GVN on trees.  */
  int flag_tree_gvn = 0;
*************** process_options (void)
*** 2331,2338 ****
      warning ("this target machine does not have delayed branches");
  #endif
  
-   if (flag_tree_based_profiling && flag_test_coverage)
-     sorry ("test-coverage not yet implemented in trees.");
    if (flag_tree_based_profiling && flag_profile_values)
      sorry ("value-based profiling not yet implemented in trees.");
  
--- 2331,2336 ----
Index: tree-cfg.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-cfg.c,v
retrieving revision 1.1.4.267.2.7
diff -c -3 -p -r1.1.4.267.2.7 tree-cfg.c
*** tree-cfg.c	7 Mar 2004 22:23:55 -0000	1.1.4.267.2.7
--- tree-cfg.c	15 Mar 2004 16:54:25 -0000
*************** make_edges (void)
*** 473,480 ****
    /* To speed up statement iterator walks, we first purge dead labels.  */
    cleanup_dead_labels ();
  
!   /* Clean up the graph and warn for unreachable code.  */
!   cleanup_tree_cfg ();
  }
  
  /* Create edges for control statement at basic block BB.  */
--- 473,481 ----
    /* To speed up statement iterator walks, we first purge dead labels.  */
    cleanup_dead_labels ();
  
!   /* We can not do complette cleanup here as it would mess up coverage info.
!      */
!   delete_unreachable_blocks ();
  }
  
  /* Create edges for control statement at basic block BB.  */
*************** make_goto_expr_edges (basic_block bb)
*** 681,686 ****
--- 682,696 ----
        if (simple_goto_p (goto_t))
  	{
  	  make_edge (bb, label_to_block (dest), EDGE_FALLTHRU);
+ 
+ 	  /* Preserve the line number information.  */
+ 	  if (EXPR_LOCUS (goto_t))
+ 	    {
+ 	      tree stmt = build_empty_stmt ();
+ 	      SET_EXPR_LOCUS (stmt, EXPR_LOCUS (goto_t));
+ 	      bsi_insert_before (&last, stmt, BSI_NEW_STMT);
+ 	      bsi_next (&last);
+ 	    }
  	  bsi_remove (&last);
  	  return;
  	}
*************** tree_find_edge_insert_loc (edge e, block
*** 2783,2788 ****
--- 2793,2814 ----
        tmp = bsi_stmt (*bsi);
        if (!stmt_ends_bb_p (tmp))
  	return true;
+ 
+       /* Insert code just before returning the value.  We may need to decompose
+          the return in the case it contains non-trivial operand.  */
+       if (TREE_CODE (tmp) == RETURN_EXPR)
+         {
+ 	  tree op = TREE_OPERAND (tmp, 0);
+ 	  if (!is_gimple_val (op))
+ 	    {
+ 	      if (TREE_CODE (op) != MODIFY_EXPR)
+ 		abort ();
+ 	      bsi_insert_before (bsi, op, BSI_NEW_STMT);
+ 	      TREE_OPERAND (tmp, 0) = TREE_OPERAND (op, 0);
+ 	    }
+ 	  bsi_prev (bsi);
+ 	  return true;
+         }
      }
  
    /* Otherwise, create a new basic block, and split this edge.  */
Index: tree-optimize.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-optimize.c,v
retrieving revision 1.1.4.122.2.8
diff -c -3 -p -r1.1.4.122.2.8 tree-optimize.c
*** tree-optimize.c	7 Mar 2004 22:23:55 -0000	1.1.4.122.2.8
--- tree-optimize.c	15 Mar 2004 16:54:25 -0000
*************** init_tree_optimization_passes (void)
*** 306,311 ****
--- 306,312 ----
    NEXT_PASS (pass_lower_cf);
    NEXT_PASS (pass_lower_eh);
    NEXT_PASS (pass_build_cfg);
+   NEXT_PASS (pass_tree_profile);
    NEXT_PASS (pass_all_optimizations);
    NEXT_PASS (pass_del_cfg);
    NEXT_PASS (pass_mudflap_2);
*************** init_tree_optimization_passes (void)
*** 313,319 ****
    *p = NULL;
  
    p = &pass_all_optimizations.sub;
-   NEXT_PASS (pass_tree_profile);
    NEXT_PASS (pass_referenced_vars);
    NEXT_PASS (pass_build_pta);
    NEXT_PASS (pass_build_ssa);
--- 314,319 ----
Index: tree-profile.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-profile.c,v
retrieving revision 1.1.4.2
diff -c -3 -p -r1.1.4.2 tree-profile.c
*** tree-profile.c	3 Mar 2004 14:18:18 -0000	1.1.4.2
--- tree-profile.c	15 Mar 2004 16:54:25 -0000
*************** tree_gen_const_delta_profiler (struct hi
*** 147,158 ****
     Gate for pass_tree_profile.  */
  
  static bool do_tree_profiling (void) {
!   if (flag_tree_based_profiling)
      {
        tree_register_profile_hooks ();
        tree_register_value_prof_hooks ();
      }
!   return flag_tree_based_profiling;
  }
  
  /* Return the file on which profile dump output goes, if any.  */
--- 147,160 ----
     Gate for pass_tree_profile.  */
  
  static bool do_tree_profiling (void) {
!   if (flag_tree_based_profiling
!       && (profile_arc_flag || flag_test_coverage || flag_branch_probabilities))
      {
        tree_register_profile_hooks ();
        tree_register_value_prof_hooks ();
+       return true;
      }
!   return false;
  }
  
  /* Return the file on which profile dump output goes, if any.  */
Index: testsuite/ChangeLog.profiling
===================================================================
RCS file: testsuite/ChangeLog.profiling
diff -N testsuite/ChangeLog.profiling
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/ChangeLog.profiling	15 Mar 2004 16:54:26 -0000
***************
*** 0 ****
--- 1,4 ----
+ 2004-03-15  Jan Hubicka  <jh@suse.cz>
+ 
+ 	* g++.dg/gcov/gcov-1.C: Fix switch statement probabilities.
+ 	* gcc.misc-tests/gcov/gcov-4b.c: Fix switch statement probabilities.
Index: testsuite/g++.dg/gcov/gcov-1.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.dg/gcov/gcov-1.C,v
retrieving revision 1.1.10.1
diff -c -3 -p -r1.1.10.1 gcov-1.C
*** testsuite/g++.dg/gcov/gcov-1.C	9 Apr 2003 19:28:53 -0000	1.1.10.1
--- testsuite/g++.dg/gcov/gcov-1.C	15 Mar 2004 16:54:27 -0000
*************** test_switch (int i, int j)
*** 253,259 ****
  {
    int result = 0;			/* count(5) */
  
! 					/* branch(80 25) */
    switch (i)				/* count(5) */
  					/* branch(end) */
      {
--- 253,259 ----
  {
    int result = 0;			/* count(5) */
  
! 					/* branch(20 0 60 20) */
    switch (i)				/* count(5) */
  					/* branch(end) */
      {


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