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]

Re: [PATCH] Value profile based optimizations, part 1


Hello,

here is the new version of the patch updated for your comments.

Zdenek

Index: Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Makefile.in,v
retrieving revision 1.1077
diff -c -3 -p -r1.1077 Makefile.in
*** Makefile.in	10 Jun 2003 00:52:11 -0000	1.1077
--- Makefile.in	13 Jun 2003 12:20:06 -0000
*************** OBJS = alias.o bb-reorder.o bitmap.o bui
*** 821,827 ****
   sibcall.o simplify-rtx.o sreal.o ssa.o ssa-ccp.o ssa-dce.o stmt.o	   \
   stor-layout.o stringpool.o timevar.o toplev.o tracer.o tree.o tree-dump.o \
   tree-inline.o unroll.o varasm.o varray.o version.o vmsdbgout.o xcoffout.o \
!  alloc-pool.o et-forest.o cgraph.o cgraphunit.o cfghooks.o		   \
   $(GGC) $(out_object_file) $(EXTRA_OBJS) $(host_hook_obj)
  
  BACKEND = main.o libbackend.a
--- 821,827 ----
   sibcall.o simplify-rtx.o sreal.o ssa.o ssa-ccp.o ssa-dce.o stmt.o	   \
   stor-layout.o stringpool.o timevar.o toplev.o tracer.o tree.o tree-dump.o \
   tree-inline.o unroll.o varasm.o varray.o version.o vmsdbgout.o xcoffout.o \
!  alloc-pool.o et-forest.o cgraph.o cgraphunit.o cfghooks.o value-prof.o	   \
   $(GGC) $(out_object_file) $(EXTRA_OBJS) $(host_hook_obj)
  
  BACKEND = main.o libbackend.a
*************** STAGESTUFF = *$(objext) insn-flags.h ins
*** 853,859 ****
  LIB2FUNCS_ST = _eprintf __gcc_bcmp
  
  # Defined in libgcov.c, included only in gcov library
! LIBGCOV = _gcov _gcov_merge_add
  
  FPBIT_FUNCS = _pack_sf _unpack_sf _addsub_sf _mul_sf _div_sf \
      _fpcmp_parts_sf _compare_sf _eq_sf _ne_sf _gt_sf _ge_sf \
--- 853,859 ----
  LIB2FUNCS_ST = _eprintf __gcc_bcmp
  
  # Defined in libgcov.c, included only in gcov library
! LIBGCOV = _gcov _gcov_merge_add _gcov_merge_single _gcov_merge_delta
  
  FPBIT_FUNCS = _pack_sf _unpack_sf _addsub_sf _mul_sf _div_sf \
      _fpcmp_parts_sf _compare_sf _eq_sf _ne_sf _gt_sf _ge_sf \
*************** conflict.o : conflict.c $(CONFIG_H) $(SY
*** 1634,1640 ****
     $(HASHTAB_H) $(RTL_H) hard-reg-set.h $(BASIC_BLOCK_H)
  profile.o : profile.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
     $(TREE_H) flags.h output.h $(REGS_H) $(EXPR_H) function.h \
!    toplev.h $(BASIC_BLOCK_H) $(COVERAGE_H)
  loop.o : loop.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_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 cfgloop.h \
--- 1634,1643 ----
     $(HASHTAB_H) $(RTL_H) hard-reg-set.h $(BASIC_BLOCK_H)
  profile.o : profile.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
     $(TREE_H) flags.h output.h $(REGS_H) $(EXPR_H) function.h \
!    toplev.h $(BASIC_BLOCK_H) $(COVERAGE_H) $(TREE_H) value-prof.h
! value-prof.o : value-prof.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
!    $(BASIC_BLOCK_H) hard-reg-set.h value-prof.h $(EXPR_H) output.h flags.h \
!    $(RECOG_H) insn-config.h $(OPTABS_H)
  loop.o : loop.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_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 cfgloop.h \
Index: flags.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/flags.h,v
retrieving revision 1.110
diff -c -3 -p -r1.110 flags.h
*** flags.h	3 Jun 2003 09:06:46 -0000	1.110
--- flags.h	13 Jun 2003 12:20:06 -0000
*************** extern int profile_flag;
*** 197,202 ****
--- 197,206 ----
  
  extern int profile_arc_flag;
  
+ /* Nonzero if value profile should be measured.  */
+ 
+ extern int flag_profile_values;
+ 
  /* Nonzero if generating info for gcov to calculate line test coverage.  */
  
  extern int flag_test_coverage;
Index: flow.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/flow.c,v
retrieving revision 1.551
diff -c -3 -p -r1.551 flow.c
*** flow.c	3 Jun 2003 23:17:27 -0000	1.551
--- flow.c	13 Jun 2003 12:20:06 -0000
*************** mark_used_regs (pbi, x, cond, insn)
*** 3843,3849 ****
  
      case SUBREG:
  #ifdef CANNOT_CHANGE_MODE_CLASS
!       if (GET_CODE (SUBREG_REG (x)) == REG
  	  && REGNO (SUBREG_REG (x)) >= FIRST_PSEUDO_REGISTER)
  	bitmap_set_bit (&subregs_of_mode, REGNO (SUBREG_REG (x))
  					  * MAX_MACHINE_MODE
--- 3843,3850 ----
  
      case SUBREG:
  #ifdef CANNOT_CHANGE_MODE_CLASS
!       if ((flags & PROP_REG_INFO)
! 	  && GET_CODE (SUBREG_REG (x)) == REG
  	  && REGNO (SUBREG_REG (x)) >= FIRST_PSEUDO_REGISTER)
  	bitmap_set_bit (&subregs_of_mode, REGNO (SUBREG_REG (x))
  					  * MAX_MACHINE_MODE
*************** mark_used_regs (pbi, x, cond, insn)
*** 3892,3898 ****
  	       || GET_CODE (testreg) == SUBREG)
  	  {
  #ifdef CANNOT_CHANGE_MODE_CLASS
! 	    if (GET_CODE (testreg) == SUBREG
  		&& GET_CODE (SUBREG_REG (testreg)) == REG
  		&& REGNO (SUBREG_REG (testreg)) >= FIRST_PSEUDO_REGISTER)
  	      bitmap_set_bit (&subregs_of_mode, REGNO (SUBREG_REG (testreg))
--- 3893,3900 ----
  	       || GET_CODE (testreg) == SUBREG)
  	  {
  #ifdef CANNOT_CHANGE_MODE_CLASS
! 	    if ((flags & PROP_REG_INFO)
! 		&& GET_CODE (testreg) == SUBREG
  		&& GET_CODE (SUBREG_REG (testreg)) == REG
  		&& REGNO (SUBREG_REG (testreg)) >= FIRST_PSEUDO_REGISTER)
  	      bitmap_set_bit (&subregs_of_mode, REGNO (SUBREG_REG (testreg))
Index: gcov-io.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gcov-io.h,v
retrieving revision 1.35
diff -c -3 -p -r1.35 gcov-io.h
*** gcov-io.h	12 Jun 2003 19:01:06 -0000	1.35
--- gcov-io.h	13 Jun 2003 12:20:06 -0000
*************** typedef HOST_WIDEST_INT gcov_type;
*** 269,281 ****
  #define GCOV_COUNTER_ARCS 	0  /* Arc transitions.  */
  #define GCOV_COUNTERS_SUMMABLE	1  /* Counters which can be
  				      summaried. */
! #define GCOV_COUNTERS		1
  
  /* A list of human readable names of the counters */
! #define GCOV_COUNTER_NAMES	{"arcs"}
  
  /* Names of merge functions for counters.  */
! #define GCOV_MERGE_FUNCTIONS	{"__gcov_merge_add"}
  
  /* Convert a counter index to a tag. */
  #define GCOV_TAG_FOR_COUNTER(COUNT)				\
--- 269,291 ----
  #define GCOV_COUNTER_ARCS 	0  /* Arc transitions.  */
  #define GCOV_COUNTERS_SUMMABLE	1  /* Counters which can be
  				      summaried. */
! #define GCOV_COUNTER_V_INTERVAL	2  /* Histogram of value inside an interval.  */
! #define GCOV_COUNTER_V_POW2	3  /* Histogram of exact power2 logarithm
! 				      of a value.  */
! #define GCOV_COUNTER_V_SINGLE	4  /* The most common value of expression.  */
! #define GCOV_COUNTER_V_DELTA	5  /* The most common difference between
! 				      consecutive values of expression.  */
! #define GCOV_COUNTERS		5
  
  /* A list of human readable names of the counters */
! #define GCOV_COUNTER_NAMES	{"arcs", "interval", "pow2", "one", "delta"}
  
  /* Names of merge functions for counters.  */
! #define GCOV_MERGE_FUNCTIONS	{"__gcov_merge_add",	\
! 				 "__gcov_merge_add",	\
! 				 "__gcov_merge_add",	\
! 				 "__gcov_merge_single",	\
! 				 "__gcov_merge_delta"}
  
  /* Convert a counter index to a tag. */
  #define GCOV_TAG_FOR_COUNTER(COUNT)				\
*************** extern void __gcov_flush (void);
*** 380,385 ****
--- 390,402 ----
  
  /* The merge function that just sums the counters.  */
  extern void __gcov_merge_add (gcov_type *, unsigned);
+ 
+ /* The merge function to choose the most often value.  */
+ extern void __gcov_merge_single (gcov_type *, unsigned);
+ 
+ /* The merge function to choose the most often difference between consecutive
+    values.  */
+ extern void __gcov_merge_delta (gcov_type *, unsigned);
  #endif /* IN_LIBGCOV */
  
  #if IN_LIBGCOV >= 0
Index: libgcov.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/libgcov.c,v
retrieving revision 1.15
diff -c -3 -p -r1.15 libgcov.c
*** libgcov.c	14 May 2003 16:01:20 -0000	1.15
--- libgcov.c	13 Jun 2003 12:20:06 -0000
*************** void __gcov_merge_add (gcov_type *counte
*** 63,68 ****
--- 63,78 ----
  		       unsigned n_counters __attribute__ ((unused))) {}
  #endif
  
+ #ifdef L_gcov_merge_single
+ void __gcov_merge_single (gcov_type *counters  __attribute__ ((unused)),
+ 			  unsigned n_counters __attribute__ ((unused))) {}
+ #endif
+ 
+ #ifdef L_gcov_merge_delta
+ void __gcov_merge_delta (gcov_type *counters  __attribute__ ((unused)),
+ 			 unsigned n_counters __attribute__ ((unused))) {}
+ #endif
+ 
  #else
  
  #include <string.h>
*************** __gcov_merge_add (gcov_type *counters, u
*** 465,469 ****
--- 475,558 ----
      *counters += gcov_read_counter ();
  }
  #endif /* L_gcov_merge_add */
+ 
+ #ifdef L_gcov_merge_single
+ /* The profile merging function for choosing the most common value.  It is given
+    an array COUNTERS of N_COUNTERS old counters and it reads the same number
+    of counters from the gcov file.  The counters are split into 3-tuples
+    where the members of the tuple have meanings:
+    -- the stored candidate on the most common value of the measured entity
+    -- counter
+    -- total number of evaluations of the value  */
+ void
+ __gcov_merge_single (gcov_type *counters, unsigned n_counters)
+ {
+   unsigned i, n_measures;
+   gcov_type value, counter, all;
+ 
+   if (n_counters % 3)
+     abort ();
+ 
+   n_measures = n_counters / 3;
+   for (i = 0; i < n_measures; i++, counters += 3)
+     {
+       value = gcov_read_counter ();
+       counter = gcov_read_counter ();
+       all = gcov_read_counter ();
+ 
+       if (counters[0] == value)
+ 	counters[1] += counter;
+       else if (counter > counters[1])
+ 	{
+ 	  counters[0] = value;
+ 	  counters[1] = counter - counters[1];
+ 	}
+       else
+ 	counters[1] -= counter;
+       counters[2] += all;
+     }
+ }
+ #endif /* L_gcov_merge_single */
+ 
+ #ifdef L_gcov_merge_delta
+ /* The profile merging function for choosing the most common difference between
+    two consecutive evaluations of the value.  It is given an array COUNTERS of
+    N_COUNTERS old counters and it reads the same number of counters from the
+    gcov file.  The counters are split into 4-tuples where the members of the
+    tuple have meanings:
+    -- the last value of the measured entity
+    -- the stored candidate on the most common difference
+    -- counter
+    -- total number of evaluations of the value  */
+ void
+ __gcov_merge_delta (gcov_type *counters, unsigned n_counters)
+ {
+   unsigned i, n_measures;
+   gcov_type last, value, counter, all;
+ 
+   if (n_counters % 4)
+     abort ();
+ 
+   n_measures = n_counters / 4;
+   for (i = 0; i < n_measures; i++, counters += 4)
+     {
+       last = gcov_read_counter ();
+       value = gcov_read_counter ();
+       counter = gcov_read_counter ();
+       all = gcov_read_counter ();
+ 
+       if (counters[1] == value)
+ 	counters[2] += counter;
+       else if (counter > counters[2])
+ 	{
+ 	  counters[1] = value;
+ 	  counters[2] = counter - counters[2];
+ 	}
+       else
+ 	counters[2] -= counter;
+       counters[3] += all;
+     }
+ }
+ #endif /* L_gcov_merge_delta */
  
  #endif /* inhibit_libc */
Index: profile.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/profile.c,v
retrieving revision 1.120
diff -c -3 -p -r1.120 profile.c
*** profile.c	11 May 2003 19:21:32 -0000	1.120
--- profile.c	13 Jun 2003 12:20:06 -0000
*************** Software Foundation, 59 Temple Place - S
*** 60,65 ****
--- 60,67 ----
  #include "function.h"
  #include "toplev.h"
  #include "coverage.h"
+ #include "value-prof.h"
+ #include "tree.h"
  
  /* Additional information about the edges we need.  */
  struct edge_info {
*************** static int total_num_branches;
*** 105,111 ****
--- 107,118 ----
  /* Forward declarations.  */
  static void find_spanning_tree PARAMS ((struct edge_list *));
  static rtx gen_edge_profiler PARAMS ((int));
+ static rtx gen_interval_profiler (struct histogram_value *, unsigned, unsigned);
+ static rtx gen_pow2_profiler (struct histogram_value *, unsigned, unsigned);
+ static rtx gen_one_value_profiler (struct histogram_value *, unsigned, unsigned);
+ static rtx gen_const_delta_profiler (struct histogram_value *, unsigned, unsigned);
  static unsigned instrument_edges PARAMS ((struct edge_list *));
+ static void instrument_values (unsigned, struct histogram_value *);
  static void compute_branch_probabilities PARAMS ((void));
  static gcov_type * get_exec_counts PARAMS ((void));
  static basic_block find_group PARAMS ((basic_block));
*************** instrument_edges (el)
*** 157,166 ****
      fprintf (rtl_dump_file, "%d edges instrumented\n", num_instr_edges);
    return num_instr_edges;
  }
  
  
! /* Computes hybrid profile for all matching entries in da_file.
!    Sets max_counter_in_program as a side effect.  */
  
  static gcov_type *
  get_exec_counts ()
--- 164,236 ----
      fprintf (rtl_dump_file, "%d edges instrumented\n", num_instr_edges);
    return num_instr_edges;
  }
+ 
+ /* Add code to measure histograms list of VALUES of length N_VALUES.  */
+ static void
+ instrument_values (unsigned n_values, struct histogram_value *values)
+ {
+   rtx sequence;
+   unsigned i, t;
+   edge e;
+  
+   /* Emit code to generate the histograms before the insns.  */
+ 
+   for (i = 0; i < n_values; i++)
+     {
+       e = split_block (BLOCK_FOR_INSN (values[i].insn),
+ 		       PREV_INSN (values[i].insn));
+       switch (values[i].type)
+ 	{
+ 	case HIST_TYPE_INTERVAL:
+ 	  t = GCOV_COUNTER_V_INTERVAL;
+ 	  break;
+ 
+ 	case HIST_TYPE_POW2:
+ 	  t = GCOV_COUNTER_V_POW2;
+ 	  break;
+ 
+ 	case HIST_TYPE_ONE_VALUE:
+ 	  t = GCOV_COUNTER_V_SINGLE;
+ 	  break;
+ 
+ 	case HIST_TYPE_CONST_DELTA:
+ 	  t = GCOV_COUNTER_V_DELTA;
+ 	  break;
+ 
+ 	default:
+ 	  abort ();
+ 	}
+       if (!coverage_counter_alloc (t, values[i].n_counters))
+ 	continue;
+ 
+       switch (values[i].type)
+ 	{
+ 	case HIST_TYPE_INTERVAL:
+ 	  sequence = gen_interval_profiler (values + i, t, 0);
+ 	  break;
+ 
+ 	case HIST_TYPE_POW2:
+ 	  sequence = gen_pow2_profiler (values + i, t, 0);
+ 	  break;
+ 
+ 	case HIST_TYPE_ONE_VALUE:
+ 	  sequence = gen_one_value_profiler (values + i, t, 0);
+ 	  break;
+ 
+ 	case HIST_TYPE_CONST_DELTA:
+ 	  sequence = gen_const_delta_profiler (values + i, t, 0);
+ 	  break;
+ 
+ 	default:
+ 	  abort ();
+ 	}
+ 
+       safe_insert_insn_on_edge (sequence, e);
+     }
+ }
  
  
! /* Computes hybrid profile for all matching entries in da_file.  */
  
  static gcov_type *
  get_exec_counts ()
*************** branch_prob ()
*** 553,558 ****
--- 623,630 ----
    unsigned num_edges, ignored_edges;
    unsigned num_instrumented;
    struct edge_list *el;
+   unsigned n_values = 0;
+   struct histogram_value *values = NULL;
  
    total_num_times_called++;
  
*************** branch_prob ()
*** 804,809 ****
--- 876,888 ----
    EXIT_BLOCK_PTR->index = EXIT_BLOCK;
  #undef BB_TO_GCOV_INDEX
  
+   if (flag_profile_values)
+     {
+       life_analysis (get_insns (), NULL, PROP_DEATH_NOTES);
+       find_values_to_profile (&n_values, &values);
+       allocate_reg_info (max_reg_num (), FALSE, FALSE);
+     }
+ 
    if (flag_branch_probabilities)
      compute_branch_probabilities ();
  
*************** branch_prob ()
*** 816,826 ****
--- 895,910 ----
        if (n_instrumented != num_instrumented)
  	abort ();
  
+       if (flag_profile_values)
+ 	instrument_values (n_values, values);
+ 
        /* Commit changes done by instrumentation.  */
        commit_edge_insertions_watch_calls ();
        allocate_reg_info (max_reg_num (), FALSE, FALSE);
      }
  
+   if (flag_profile_values)
+     count_or_remove_death_notes (NULL, 1);
    remove_fake_edges ();
    free_aux_for_edges ();
    /* Re-merge split basic blocks and the mess introduced by
*************** gen_edge_profiler (edgeno)
*** 1027,1031 ****
--- 1111,1413 ----
  
    sequence = get_insns ();
    end_sequence ();
+   return sequence;
+ }
+ 
+ /* Output instructions as RTL to increment the interval histogram counter.
+    VALUE is the expression whose value is profiled.  TAG is the tag of the
+    section for counters, BASE is offset of the counter position.  */
+ 
+ static rtx
+ gen_interval_profiler (struct histogram_value *value,
+ 		       unsigned tag, unsigned base)
+ {
+   unsigned gcov_size = tree_low_cst (TYPE_SIZE (GCOV_TYPE_NODE), 1);
+   enum machine_mode mode = mode_for_size (gcov_size, MODE_INT, 0);
+   rtx mem_ref, tmp, tmp1, mr, val;
+   rtx sequence;
+   rtx more_label = gen_label_rtx ();
+   rtx less_label = gen_label_rtx ();
+   rtx end_of_code_label = gen_label_rtx ();
+   int per_counter = gcov_size / BITS_PER_UNIT;
+ 
+   start_sequence ();
+ 
+   if (value->seq)
+     emit_insn (value->seq);
+ 
+   mr = gen_reg_rtx (Pmode);
+ 
+   tmp = coverage_counter_ref (tag, base);
+   tmp = force_reg (Pmode, XEXP (tmp, 0));
+ 
+   val = expand_simple_binop (value->mode, MINUS,
+ 			     copy_rtx (value->value),
+ 			     GEN_INT (value->hdata.intvl.int_start),
+ 			     NULL_RTX, 0, OPTAB_WIDEN);
+ 
+   if (value->hdata.intvl.may_be_more)
+     do_compare_rtx_and_jump (copy_rtx (val), GEN_INT (value->hdata.intvl.steps),
+ 			     GE, 0, value->mode, NULL_RTX, NULL_RTX, more_label);
+   if (value->hdata.intvl.may_be_less)
+     do_compare_rtx_and_jump (copy_rtx (val), const0_rtx, LT, 0, value->mode,
+ 			     NULL_RTX, NULL_RTX, less_label);
+ 
+   /* We are in range.  */
+   tmp1 = expand_simple_binop (value->mode, MULT,
+ 			      copy_rtx (val), GEN_INT (per_counter),
+ 			      NULL_RTX, 0, OPTAB_WIDEN);
+   tmp1 = expand_simple_binop (Pmode, PLUS, copy_rtx (tmp), tmp1, mr,
+ 			      0, OPTAB_WIDEN);
+   if (tmp1 != mr)
+     emit_move_insn (copy_rtx (mr), tmp1);
+ 
+   if (value->hdata.intvl.may_be_more
+       || value->hdata.intvl.may_be_less)
+     {
+       emit_jump_insn (gen_jump (end_of_code_label));
+       emit_barrier ();
+     }
+ 
+   /* Above the interval.  */
+   if (value->hdata.intvl.may_be_more)
+     {
+       emit_label (more_label);
+       tmp1 = expand_simple_binop (Pmode, PLUS, copy_rtx (tmp),
+ 				  GEN_INT (per_counter * value->hdata.intvl.steps),
+     				  mr, 0, OPTAB_WIDEN);
+       if (tmp1 != mr)
+ 	emit_move_insn (copy_rtx (mr), tmp1);
+       if (value->hdata.intvl.may_be_less)
+ 	{
+ 	  emit_jump_insn (gen_jump (end_of_code_label));
+ 	  emit_barrier ();
+ 	}
+     }
+ 
+   /* Below the interval.  */
+   if (value->hdata.intvl.may_be_less)
+     {
+       emit_label (less_label);
+       tmp1 = expand_simple_binop (Pmode, PLUS, copy_rtx (tmp),
+ 		GEN_INT (per_counter * (value->hdata.intvl.steps
+ 					+ (value->hdata.intvl.may_be_more ? 1 : 0))),
+ 		mr, 0, OPTAB_WIDEN);
+       if (tmp1 != mr)
+ 	emit_move_insn (copy_rtx (mr), tmp1);
+     }
+ 
+   if (value->hdata.intvl.may_be_more
+       || value->hdata.intvl.may_be_less)
+     emit_label (end_of_code_label);
+ 
+   mem_ref = validize_mem (gen_rtx_MEM (mode, mr));
+ 
+   tmp = expand_simple_binop (mode, PLUS, copy_rtx (mem_ref), const1_rtx,
+ 			     mem_ref, 0, OPTAB_WIDEN);
+ 
+   if (tmp != mem_ref)
+     emit_move_insn (copy_rtx (mem_ref), tmp);
+ 
+   sequence = get_insns ();
+   end_sequence ();
+   rebuild_jump_labels (sequence);
+   return sequence;
+ }
+ 
+ /* Output instructions as RTL to increment the power of two histogram counter.
+    VALUE is the expression whose value is profiled.  TAG is the tag of the
+    section for counters, BASE is offset of the counter position.  */
+ 
+ static rtx
+ gen_pow2_profiler (struct histogram_value *value,
+ 		   unsigned tag, unsigned base)
+ {
+   unsigned gcov_size = tree_low_cst (TYPE_SIZE (GCOV_TYPE_NODE), 1);
+   enum machine_mode mode = mode_for_size (gcov_size, MODE_INT, 0);
+   rtx mem_ref, tmp, mr, uval;
+   rtx sequence;
+   rtx end_of_code_label = gen_label_rtx ();
+   rtx loop_label = gen_label_rtx ();
+   int per_counter = gcov_size / BITS_PER_UNIT;
+ 
+   start_sequence ();
+ 
+   if (value->seq)
+     emit_insn (value->seq);
+ 
+   mr = gen_reg_rtx (Pmode);
+   tmp = coverage_counter_ref (tag, base);
+   tmp = force_reg (Pmode, XEXP (tmp, 0));
+   emit_move_insn (mr, tmp);
+ 
+   uval = gen_reg_rtx (value->mode);
+   emit_move_insn (uval, copy_rtx (value->value));
+ 
+   /* Check for non-power of 2.  */
+   if (value->hdata.pow2.may_be_other)
+     {
+       do_compare_rtx_and_jump (copy_rtx (uval), const0_rtx, LE, 0, value->mode,
+ 			       NULL_RTX, NULL_RTX, end_of_code_label);
+       tmp = expand_simple_binop (value->mode, PLUS, copy_rtx (uval),
+ 				 constm1_rtx, NULL_RTX, 0, OPTAB_WIDEN);
+       tmp = expand_simple_binop (value->mode, AND, copy_rtx (uval), tmp,
+ 				 NULL_RTX, 0, OPTAB_WIDEN);
+       do_compare_rtx_and_jump (tmp, const0_rtx, NE, 0, value->mode, NULL_RTX,
+     			       NULL_RTX, end_of_code_label);
+     }
+ 
+   /* Count log_2(value).  */
+   emit_label (loop_label);
+ 
+   tmp = expand_simple_binop (Pmode, PLUS, copy_rtx (mr), GEN_INT (per_counter), mr, 0, OPTAB_WIDEN);
+   if (tmp != mr)
+     emit_move_insn (copy_rtx (mr), tmp);
+ 
+   tmp = expand_simple_binop (value->mode, ASHIFTRT, copy_rtx (uval), const1_rtx,
+ 			     uval, 0, OPTAB_WIDEN);
+   if (tmp != uval)
+     emit_move_insn (copy_rtx (uval), tmp);
+ 
+   do_compare_rtx_and_jump (copy_rtx (uval), const0_rtx, NE, 0, value->mode,
+ 			   NULL_RTX, NULL_RTX, loop_label);
+ 
+   /* Increase the counter.  */
+   emit_label (end_of_code_label);
+ 
+   mem_ref = validize_mem (gen_rtx_MEM (mode, mr));
+ 
+   tmp = expand_simple_binop (mode, PLUS, copy_rtx (mem_ref), const1_rtx,
+ 			     mem_ref, 0, OPTAB_WIDEN);
+ 
+   if (tmp != mem_ref)
+     emit_move_insn (copy_rtx (mem_ref), tmp);
+ 
+   sequence = get_insns ();
+   end_sequence ();
+   rebuild_jump_labels (sequence);
+   return sequence;
+ }
+ 
+ /* Output instructions as RTL for code to find the most common value.
+    VALUE is the expression whose value is profiled.  TAG is the tag of the
+    section for counters, BASE is offset of the counter position.  */
+ 
+ static rtx
+ gen_one_value_profiler (struct histogram_value *value,
+ 			unsigned tag, unsigned base)
+ {
+   unsigned gcov_size = tree_low_cst (TYPE_SIZE (GCOV_TYPE_NODE), 1);
+   enum machine_mode mode = mode_for_size (gcov_size, MODE_INT, 0);
+   rtx stored_value_ref, counter_ref, all_ref, stored_value, counter, all;
+   rtx tmp, uval;
+   rtx sequence;
+   rtx same_label = gen_label_rtx ();
+   rtx zero_label = gen_label_rtx ();
+   rtx end_of_code_label = gen_label_rtx ();
+ 
+   start_sequence ();
+ 
+   if (value->seq)
+     emit_insn (value->seq);
+ 
+   stored_value_ref = coverage_counter_ref (tag, base);
+   counter_ref = coverage_counter_ref (tag, base + 1);
+   all_ref = coverage_counter_ref (tag, base + 2);
+   stored_value = validize_mem (stored_value_ref);
+   counter = validize_mem (counter_ref);
+   all = validize_mem (all_ref);
+ 
+   uval = gen_reg_rtx (mode);
+   convert_move (uval, copy_rtx (value->value), 0);
+ 
+   /* Check if the stored value matches.  */
+   do_compare_rtx_and_jump (copy_rtx (uval), copy_rtx (stored_value), EQ,
+ 			   0, mode, NULL_RTX, NULL_RTX, same_label);
+   
+   /* Does not match; check whether the counter is zero.  */
+   do_compare_rtx_and_jump (copy_rtx (counter), const0_rtx, EQ, 0, mode,
+ 			   NULL_RTX, NULL_RTX, zero_label);
+ 
+   /* The counter is not zero yet.  */
+   tmp = expand_simple_binop (mode, PLUS, copy_rtx (counter), constm1_rtx,
+ 			     counter, 0, OPTAB_WIDEN);
+ 
+   if (tmp != counter)
+     emit_move_insn (copy_rtx (counter), tmp);
+ 
+   emit_jump_insn (gen_jump (end_of_code_label));
+   emit_barrier ();
+  
+   emit_label (zero_label);
+   /* Set new value.  */
+   emit_move_insn (copy_rtx (stored_value), copy_rtx (uval));
+ 
+   emit_label (same_label);
+   /* Increase the counter.  */
+   tmp = expand_simple_binop (mode, PLUS, copy_rtx (counter), const1_rtx,
+ 			     counter, 0, OPTAB_WIDEN);
+ 
+   if (tmp != counter)
+     emit_move_insn (copy_rtx (counter), tmp);
+   
+   emit_label (end_of_code_label);
+ 
+   /* Increase the counter of all executions; this seems redundant given
+      that ve have counts for edges in cfg, but it may happen that some
+      optimization will change the counts for the block (either because
+      it is unable to update them correctly, or because it will duplicate
+      the block or its part).  */
+   tmp = expand_simple_binop (mode, PLUS, copy_rtx (all), const1_rtx,
+ 			     all, 0, OPTAB_WIDEN);
+ 
+   if (tmp != all)
+     emit_move_insn (copy_rtx (all), tmp);
+   sequence = get_insns ();
+   end_sequence ();
+   rebuild_jump_labels (sequence);
+   return sequence;
+ }
+ 
+ /* Output instructions as RTL for code to find the most common value of
+    a difference between two evaluations of an expression.
+    VALUE is the expression whose value is profiled.  TAG is the tag of the
+    section for counters, BASE is offset of the counter position.  */
+ 
+ static rtx
+ gen_const_delta_profiler (struct histogram_value *value,
+ 			  unsigned tag, unsigned base)
+ {
+   struct histogram_value one_value_delta;
+   unsigned gcov_size = tree_low_cst (TYPE_SIZE (GCOV_TYPE_NODE), 1);
+   enum machine_mode mode = mode_for_size (gcov_size, MODE_INT, 0);
+   rtx stored_value_ref, stored_value, tmp, uval;
+   rtx sequence;
+ 
+   start_sequence ();
+ 
+   if (value->seq)
+     emit_insn (value->seq);
+ 
+   stored_value_ref = coverage_counter_ref (tag, base);
+   stored_value = validize_mem (stored_value_ref);
+ 
+   uval = gen_reg_rtx (mode);
+   convert_move (uval, copy_rtx (value->value), 0);
+   tmp = expand_simple_binop (mode, MINUS,
+ 			     copy_rtx (uval), copy_rtx (stored_value),
+ 			     NULL_RTX, 0, OPTAB_WIDEN);
+ 
+   one_value_delta.value = tmp;
+   one_value_delta.mode = mode;
+   one_value_delta.seq = NULL_RTX;
+   one_value_delta.insn = value->insn;
+   one_value_delta.type = HIST_TYPE_ONE_VALUE;
+   emit_insn (gen_one_value_profiler (&one_value_delta, tag, base + 1));
+ 
+   emit_move_insn (copy_rtx (stored_value), uval);
+   sequence = get_insns ();
+   end_sequence ();
+   rebuild_jump_labels (sequence);
    return sequence;
  }
Index: toplev.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/toplev.c,v
retrieving revision 1.769
diff -c -3 -p -r1.769 toplev.c
*** toplev.c	8 Jun 2003 19:35:53 -0000	1.769
--- toplev.c	13 Jun 2003 12:20:06 -0000
*************** int profile_flag = 0;
*** 428,433 ****
--- 428,437 ----
  
  int profile_arc_flag = 0;
  
+ /* Nonzero if value histograms should be measured.  */
+ 
+ int flag_profile_values = 0;
+ 
  /* Nonzero if generating info for gcov to calculate line test coverage.  */
  
  int flag_test_coverage = 0;
*************** static const lang_independent_options f_
*** 1185,1190 ****
--- 1189,1196 ----
     N_("Create data files needed by gcov") },
    {"branch-probabilities", &flag_branch_probabilities, 1,
     N_("Use profiling information for branch probabilities") },
+   {"profile-values", &flag_profile_values, 1,
+    N_("Insert code to profile values of expressions") },
    {"profile", &profile_flag, 1,
     N_("Enable basic program profiling code") },
    {"reorder-blocks", &flag_reorder_blocks, 1,

value-prof.c:
============================================
/* Transformations based on profile information for values.
   Copyright (C) 2003 Free Software Foundation, Inc.

This file is part of GCC.

GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.

GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING.  If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.  */

#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "rtl.h"
#include "expr.h"
#include "hard-reg-set.h"
#include "basic-block.h"
#include "value-prof.h"
#include "output.h"
#include "flags.h"
#include "insn-config.h"
#include "recog.h"
#include "optabs.h"

/* In this file value profile based optimizations will be placed (none are
   here just now, but they are hopefully coming soon).

   Every such optimization should add its requirements for profiled values to
   insn_values_to_profile function.  This function is called from branch_prob
   in profile.c and the requested values are instrumented by it in the first
   compilation with -fprofile-arcs.  The optimization may then read the
   gathered data in the second compilation with -fbranch-probablities (the
   description of an exact way how to do it will be added here once the
   code responsible for reading of the data is merged).  */

static void insn_values_to_profile (rtx, unsigned *, struct histogram_value **);

/* Release the list of VALUES of length N_VALUES for that we want to measure
   histograms.  */
void
free_profiled_values (unsigned n_values ATTRIBUTE_UNUSED,
		      struct histogram_value *values)
{
  free (values);
}

/* Find values inside INSN for that we want to measure histograms and adds
   them to list VALUES (increasing the record of its length in N_VALUES).  */
static void
insn_values_to_profile (rtx insn ATTRIBUTE_UNUSED,
			unsigned *n_values ATTRIBUTE_UNUSED,
			struct histogram_value **values ATTRIBUTE_UNUSED)
{
}

/* Find list of values for that we want to measure histograms.  */
void
find_values_to_profile (unsigned *n_values, struct histogram_value **values)
{
  rtx insn;
  unsigned i;

  *n_values = 0;
  *values = NULL;
  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
    insn_values_to_profile (insn, n_values, values);

  for (i = 0; i < *n_values; i++)
    {
      switch ((*values)[i].type)
	{
	case HIST_TYPE_INTERVAL:
	  (*values)[i].n_counters = (*values)[i].hdata.intvl.steps +
		  ((*values)[i].hdata.intvl.may_be_less ? 1 : 0) +
		  ((*values)[i].hdata.intvl.may_be_more ? 1 : 0);
	  break;

	case HIST_TYPE_POW2:
	  (*values)[i].n_counters = GET_MODE_BITSIZE ((*values)[i].mode) +
		  ((*values)[i].hdata.pow2.may_be_other ? 1 : 0);
	  break;

	case HIST_TYPE_ONE_VALUE:
	  (*values)[i].n_counters = 3;
	  break;

	case HIST_TYPE_CONST_DELTA:
	  (*values)[i].n_counters = 4;
	  break;

	default:
	  abort ();
	}
    }
}

value-prof.h:
============================================
/* Definitions for transformations based on profile information for values.
   Copyright (C) 2003 Free Software Foundation, Inc.

This file is part of GCC.

GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.

GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING.  If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.  */

/* Supported histogram types.  */
enum hist_type
{
  HIST_TYPE_INTERVAL,	/* Measures histogram of values inside a specified
			   interval.  */
  HIST_TYPE_POW2,	/* Histogram of power of 2 values.  */
  HIST_TYPE_ONE_VALUE,	/* Tries to identify the value that is (almost)
			   always constant.  */
  HIST_TYPE_CONST_DELTA	/* Tries to identify the (almost) always constant
			   difference between two evaluations of a value.  */
};

/* The value to measure.  */
struct histogram_value
{
  rtx value;		/* The value to profile.  */
  enum machine_mode mode; /* And its mode.  */
  rtx seq;		/* Insns requiered to count the profiled value.  */
  rtx insn;		/* Insn before that to measure.  */
  enum hist_type type;	/* Type of information to measure.  */
  unsigned n_counters;	/* Number of requiered counters.  */
  union
    {
      struct
	{
	  int int_start;	/* First value in interval.  */
	  int steps;		/* Number of values in it.  */
	  int may_be_less;	/* May the value be below?  */
	  int may_be_more;	/* Or above.  */
	} intvl;	/* Interval histogram data.  */
      struct
	{
	  int may_be_other;	/* If the value may be non-positive or not 2^k.  */
	} pow2;		/* Power of 2 histogram data.  */
    } hdata;		/* Profiled information specific data.  */
};

extern void find_values_to_profile (unsigned *, struct histogram_value **);
extern void free_profiled_values (unsigned, struct histogram_value *);


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