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]

[rtlopt] Value profiling and optimalizations


Hello,

this patch adds the means to measure profiles of variables and use them
for optimalizations. More concretely it gives you possibility to measure
  * histogram of value inside some specified interval
  * (untested) histogram of belonging to one of several ranges
  * how often the value is a power of 2 (and what)
  * whether the value is equal to a constant most of the time (and what)

The new vpt (Value Profile based Transformations) pass is added that
uses the data to optimize the code. For now it just does elimination
of divs and mods, but there are more simmilar transformations possible.

Zdenek

Changelog:
	* Makefile.in (vpt.o): New file.
	(toplev.o, profile.o): Add vpt.h dependecy.
	* vpt.h: New.
	* vpt.c: New.
	* combine.c (distribute_notes): Handle REG_VALUE_HISTOGRAM note.
	* flags.h (flag_value_histograms): Declare.
	* gcov-io.h (GCOV_TAG_VALUE_HISTOGRAMS): New.
	(struct function_info): Add n_value_histogram_counters field.
	(struct gcov_info): Add value_counts and n_value_counts fields.
	* libgcc2.c (gcov_exit, __gcov_flush): Write out value histograms.
	* profile.c: Include vpt.h.
	(struct function_list): Add value_counters field.
	(value_histograms_label): New.
	(gen_loop_profiler): Deleted.
	(gen_interval_profiler, gen_range_profiler, gen_pow2_profiler,
	gen_one_value_profiler): New.
	(get_histogram_counts, instrument_loops, compute_loop_histograms,
	init_branch_prob): Modified.
	(index_counts_file): Fix mistakes.
	(instrument_values, compute_value_histograms): New.
	(branch_prob): Call them.
	(create_profiler): Emit requiered structures.
	* profile.h (struct profile_info): Add count_value_counters,
	count_value_counters_now and have_value_histograms fields.
	* rtl.c (reg_note_name): Add REG_VALUE_HISTOGRAM.
	* rtl.h (enum reg_note): Ditto.
	* toplev.c: Include vpt.h.
	(enum dump_file_index, dump_file): Add vpt dump file.
	(flag_value_histograms, flag_value_profile_transformations): New.
	(lang_independent_options): Add them.
	(rest_of_compilation): Add vpt pass.

Index: Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Makefile.in,v
retrieving revision 1.937.2.7
diff -c -3 -p -r1.937.2.7 Makefile.in
*** Makefile.in	16 Nov 2002 17:32:16 -0000	1.937.2.7
--- Makefile.in	21 Nov 2002 19:38:32 -0000
*************** OBJS = alias.o bb-reorder.o bitmap.o bui
*** 755,762 ****
   sbitmap.o sched-deps.o sched-ebb.o sched-rgn.o sched-vis.o sdbout.o	   \
   sibcall.o simplify-rtx.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 \
!  et-forest.o $(GGC) $(out_object_file) $(EXTRA_OBJS)
  
  BACKEND = main.o libbackend.a
  
--- 755,762 ----
   sbitmap.o sched-deps.o sched-ebb.o sched-rgn.o sched-vis.o sdbout.o	   \
   sibcall.o simplify-rtx.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 vpt.o	   \
!  xcoffout.o et-forest.o $(GGC) $(out_object_file) $(EXTRA_OBJS)
  
  BACKEND = main.o libbackend.a
  
*************** toplev.o : toplev.c $(CONFIG_H) $(SYSTEM
*** 1391,1397 ****
     debug.h insn-config.h intl.h $(RECOG_H) Makefile toplev.h \
     dwarf2out.h sdbout.h dbxout.h $(EXPR_H) hard-reg-set.h $(BASIC_BLOCK_H) \
     graph.h $(LOOP_H) except.h $(REGS_H) $(TIMEVAR_H) $(lang_options_files) \
!    ssa.h $(PARAMS_H) $(TM_P_H) reload.h dwarf2asm.h $(TARGET_H) \
     langhooks.h insn-flags.h options.h cfglayout.h gcse-globals.h real.h
  	$(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
  	  -DTARGET_NAME=\"$(target_alias)\" \
--- 1391,1397 ----
     debug.h insn-config.h intl.h $(RECOG_H) Makefile toplev.h \
     dwarf2out.h sdbout.h dbxout.h $(EXPR_H) hard-reg-set.h $(BASIC_BLOCK_H) \
     graph.h $(LOOP_H) except.h $(REGS_H) $(TIMEVAR_H) $(lang_options_files) \
!    ssa.h $(PARAMS_H) $(TM_P_H) reload.h dwarf2asm.h $(TARGET_H) vpt.h \
     langhooks.h insn-flags.h options.h cfglayout.h gcse-globals.h real.h
  	$(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
  	  -DTARGET_NAME=\"$(target_alias)\" \
*************** profile.o : profile.c $(CONFIG_H) $(SYST
*** 1549,1555 ****
     insn-config.h output.h $(REGS_H) $(EXPR_H) function.h \
     gcov-io.h gcov-iov.h toplev.h $(GGC_H) hard-reg-set.h $(BASIC_BLOCK_H) \
     $(TARGET_H) langhooks.h profile.h libfuncs.h gt-profile.h cfgloop.h \
!    params.h $(HASHTAB_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 \
--- 1549,1557 ----
     insn-config.h output.h $(REGS_H) $(EXPR_H) function.h \
     gcov-io.h gcov-iov.h toplev.h $(GGC_H) hard-reg-set.h $(BASIC_BLOCK_H) \
     $(TARGET_H) langhooks.h profile.h libfuncs.h gt-profile.h cfgloop.h \
!    params.h $(HASHTAB_H) vpt.h
! vpt.o : vpt.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(BASIC_BLOCK_H) profile.h \
!    hard-reg-set.h vpt.h $(EXPR_H) output.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 \
Index: combine.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/combine.c,v
retrieving revision 1.310.2.4
diff -c -3 -p -r1.310.2.4 combine.c
*** combine.c	16 Nov 2002 17:32:19 -0000	1.310.2.4
--- combine.c	21 Nov 2002 19:38:32 -0000
*************** distribute_notes (notes, from_insn, i3, 
*** 12238,12243 ****
--- 12238,12248 ----
  	  place = i3;
  	  break;
  
+ 	case REG_VALUE_HISTOGRAM:
+ 	  /* Given that I don't understand what's going on here at all,
+ 	     just get rid of this.  */
+ 	  break;
+ 
  	case REG_VTABLE_REF:
  	  /* ??? Should remain with *a particular* memory load.  Given the
  	     nature of vtable data, the last insn seems relatively safe.  */
Index: flags.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/flags.h,v
retrieving revision 1.88.2.3
diff -c -3 -p -r1.88.2.3 flags.h
*** flags.h	8 Nov 2002 20:47:10 -0000	1.88.2.3
--- flags.h	21 Nov 2002 19:38:33 -0000
*************** extern int profile_arc_flag;
*** 201,206 ****
--- 201,210 ----
  
  extern int flag_loop_histograms;
  
+ /* Nonzero if generating/using value histograms.  */
+ 
+ extern int flag_value_histograms;
+ 
  /* Nonzero if generating info for gcov to calculate line test coverage.  */
  
  extern int flag_test_coverage;
Index: gcov-io.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gcov-io.h,v
retrieving revision 1.16.6.2
diff -c -3 -p -r1.16.6.2 gcov-io.h
*** gcov-io.h	8 Nov 2002 20:47:11 -0000	1.16.6.2
--- gcov-io.h	21 Nov 2002 19:38:33 -0000
*************** typedef long long gcov_type;
*** 176,181 ****
--- 176,182 ----
  #define GCOV_TAG_LINES		 ((unsigned)0x01450000)
  #define GCOV_TAG_ARC_COUNTS  	 ((unsigned)0x01a10000)
  #define GCOV_TAG_LOOP_HISTOGRAMS ((unsigned)0x01a30000)
+ #define GCOV_TAG_VALUE_HISTOGRAMS ((unsigned)0x01a50000)
  #define GCOV_TAG_OBJECT_SUMMARY  ((unsigned)0xa1000000)
  #define GCOV_TAG_PROGRAM_SUMMARY ((unsigned)0xa3000000)
  #define GCOV_TAG_PLACEHOLDER_SUMMARY ((unsigned)0xa5000000)
*************** struct function_info
*** 229,234 ****
--- 230,237 ----
    unsigned n_arc_counts;	/* number of instrumented arcs */
    unsigned n_loop_histogram_counters;
    				/* number of histogram counters */
+   unsigned n_value_histogram_counters;
+   				/* number of value histogram counters */
  };
  
  /* Information about a single object file.  */
*************** struct gcov_info
*** 247,252 ****
--- 250,257 ----
    unsigned n_arc_counts;	/* number of arc counts */
    gcov_type *histogram_counts;	/* table of loop histogram counters */
    unsigned n_histogram_counts;	/* number of histogram counts */
+   gcov_type *value_counts;	/* table of value histogram counters */
+   unsigned n_value_counts;	/* number of histogram counts */
  };
  
  /* Register a new object file module.  */
Index: libgcc2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/libgcc2.c,v
retrieving revision 1.147.2.3
diff -c -3 -p -r1.147.2.3 libgcc2.c
*** libgcc2.c	8 Nov 2002 20:47:11 -0000	1.147.2.3
--- libgcc2.c	21 Nov 2002 19:38:33 -0000
*************** gcov_exit (void)
*** 1311,1317 ****
        int merging = 0;
        long base;
        const struct function_info *fn_info;
!       gcov_type *count_ptr, *histograms_ptr;
        gcov_type object_max_one = 0;
        gcov_type count;
        unsigned tag, length, flength, checksum;
--- 1311,1317 ----
        int merging = 0;
        long base;
        const struct function_info *fn_info;
!       gcov_type *count_ptr, *histograms_ptr, *values_ptr;
        gcov_type object_max_one = 0;
        gcov_type count;
        unsigned tag, length, flength, checksum;
*************** gcov_exit (void)
*** 1375,1380 ****
--- 1375,1381 ----
  	  /* Merge execution counts for each function.  */
  	  count_ptr = ptr->arc_counts;
  	  histograms_ptr = ptr->histogram_counts;
+ 	  values_ptr = ptr->value_counts;
  	  for (ix = ptr->n_functions, fn_info = ptr->functions;
  	       ix--; fn_info++)
  	    {
*************** gcov_exit (void)
*** 1431,1436 ****
--- 1432,1451 ----
  		  goto read_error;
  		else
  		  *histograms_ptr += count;
+ 
+ 	      /* Value histograms. */ 
+ 	      if (gcov_read_unsigned (da_file, &tag)
+ 		  || gcov_read_unsigned (da_file, &length))
+ 		goto read_error;
+ 	      if (tag != GCOV_TAG_VALUE_HISTOGRAMS
+ 		  || length / 8 != fn_info->n_value_histogram_counters)
+ 		goto read_mismatch;
+ 		
+       	      for (jx = fn_info->n_value_histogram_counters; jx--; values_ptr++)
+ 		if (gcov_read_counter (da_file, &count))
+ 		  goto read_error;
+ 		else
+ 		  *values_ptr += count;
  	    }
  
  	  /* Check object summary */
*************** gcov_exit (void)
*** 1511,1516 ****
--- 1526,1532 ----
        /* Write execution counts for each function.  */
        count_ptr = ptr->arc_counts;
        histograms_ptr = ptr->histogram_counts;
+       values_ptr = ptr->value_counts;
        for (ix = ptr->n_functions, fn_info = ptr->functions; ix--; fn_info++)
  	{
  	  /* Announce function. */
*************** gcov_exit (void)
*** 1557,1562 ****
--- 1573,1594 ----
  	    }
  	  if (gcov_write_length (da_file, base))
  	    goto write_error;
+ 
+ 	  /* value histograms.  */
+ 	  if (gcov_write_unsigned (da_file, GCOV_TAG_VALUE_HISTOGRAMS)
+ 	      || !(base = gcov_reserve_length (da_file)))
+ 	    goto write_error;
+ 	  
+ 	  for (jx = fn_info->n_value_histogram_counters; jx--;)
+ 	    {
+ 	      gcov_type count = *values_ptr++;
+ 	      
+ 	      object.arc_sum += count;
+ 	      if (gcov_write_counter (da_file, count))
+ 		goto write_error;
+ 	    }
+ 	  if (gcov_write_length (da_file, base))
+ 	    goto write_error;
  	}
  
        /* Object file summary. */
*************** __gcov_flush (void)
*** 1698,1703 ****
--- 1730,1737 ----
  	ptr->arc_counts[i] = 0;
        for (i = ptr->n_histogram_counts; i--;)
  	ptr->histogram_counts[i] = 0;
+       for (i = ptr->n_value_counts; i--;)
+ 	ptr->value_counts[i] = 0;
      }
  }
  
Index: profile.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/profile.c,v
retrieving revision 1.97.2.4
diff -c -3 -p -r1.97.2.4 profile.c
*** profile.c	10 Nov 2002 13:18:40 -0000	1.97.2.4
--- profile.c	21 Nov 2002 19:38:33 -0000
*************** Software Foundation, 59 Temple Place - S
*** 70,75 ****
--- 70,76 ----
  #include "libfuncs.h"
  #include "langhooks.h"
  #include "hashtab.h"
+ #include "vpt.h"
  
  /* Additional information about the edges we need.  */
  struct edge_info {
*************** struct function_list
*** 98,103 ****
--- 99,105 ----
    unsigned cfg_checksum;	/* function checksum */
    unsigned count_edges;	        /* number of intrumented edges  */
    unsigned histogram_counters;	/* number of histogram counters  */
+   unsigned value_counters;	/* number of value histogram counters  */
  };
  
  static struct function_list *functions_head = 0;
*************** static GTY(()) rtx profiler_label;
*** 132,137 ****
--- 134,142 ----
  /* The name of the loop histograms table.  */
  static GTY(()) rtx loop_histograms_label;
  
+ /* The name of the value histograms table.  */
+ static GTY(()) rtx value_histograms_label;
+ 
  /* Collect statistics on the performance of this pass for the entire source
     file.  */
  
*************** static int total_num_branches;
*** 149,166 ****
  /* Forward declarations.  */
  static void find_spanning_tree PARAMS ((struct edge_list *));
  static rtx gen_edge_profiler PARAMS ((int));
! static rtx gen_loop_profiler PARAMS ((rtx, int, int));
  static void instrument_edges PARAMS ((struct edge_list *));
  static void instrument_loops PARAMS ((struct loops *));
  static void compute_branch_probabilities PARAMS ((void));
  static void compute_loop_histograms PARAMS ((struct loops *));
  static hashval_t htab_counts_index_hash PARAMS ((const void *));
  static int htab_counts_index_eq PARAMS ((const void *, const void *));
  static void htab_counts_index_del PARAMS ((void *));
  static void cleanup_counts_index PARAMS ((int));
  static int index_counts_file PARAMS ((void));
  static gcov_type * get_exec_counts PARAMS ((void));
! static gcov_type * get_histogram_counts PARAMS ((int, int));
  static unsigned compute_checksum PARAMS ((void));
  static basic_block find_group PARAMS ((basic_block));
  static void union_groups PARAMS ((basic_block, basic_block));
--- 154,176 ----
  /* Forward declarations.  */
  static void find_spanning_tree PARAMS ((struct edge_list *));
  static rtx gen_edge_profiler PARAMS ((int));
! static rtx gen_interval_profiler PARAMS ((struct histogram_value *, rtx, int));
! static rtx gen_range_profiler PARAMS ((struct histogram_value *, rtx, int));
! static rtx gen_pow2_profiler PARAMS ((struct histogram_value *, rtx, int));
! static rtx gen_one_value_profiler PARAMS ((struct histogram_value *, rtx, int));
  static void instrument_edges PARAMS ((struct edge_list *));
  static void instrument_loops PARAMS ((struct loops *));
+ static void instrument_values PARAMS ((unsigned, struct histogram_value *));
  static void compute_branch_probabilities PARAMS ((void));
  static void compute_loop_histograms PARAMS ((struct loops *));
+ static void compute_value_histograms PARAMS ((unsigned, struct histogram_value *));
  static hashval_t htab_counts_index_hash PARAMS ((const void *));
  static int htab_counts_index_eq PARAMS ((const void *, const void *));
  static void htab_counts_index_del PARAMS ((void *));
  static void cleanup_counts_index PARAMS ((int));
  static int index_counts_file PARAMS ((void));
  static gcov_type * get_exec_counts PARAMS ((void));
! static gcov_type * get_histogram_counts PARAMS ((unsigned, unsigned));
  static unsigned compute_checksum PARAMS ((void));
  static basic_block find_group PARAMS ((basic_block));
  static void union_groups PARAMS ((basic_block, basic_block));
*************** instrument_loops (loops)
*** 272,281 ****
  	  dest_loop = find_common_loop (src_loop, e->dest->loop_father);
  
  	  for (loop = src_loop; loop != dest_loop; loop = loop->outer)
! 	    insert_insn_on_edge (gen_loop_profiler (loop_counters[loop->num],
! 						    loop->num,
! 						    histogram_steps),
! 				 e);
  	}
      }
    free (loop_counters);
--- 282,303 ----
  	  dest_loop = find_common_loop (src_loop, e->dest->loop_father);
  
  	  for (loop = src_loop; loop != dest_loop; loop = loop->outer)
! 	    {
! 	      struct histogram_value cdesc;
! 
! 	      cdesc.value = loop_counters[loop->num];
! 	      cdesc.mode = mode;
! 	      cdesc.seq = NULL_RTX;
! 	      cdesc.hdata.intvl.int_start = 0;
! 	      cdesc.hdata.intvl.steps = histogram_steps;
! 	      cdesc.hdata.intvl.may_be_less = 0;
! 	      cdesc.hdata.intvl.may_be_more = 1;
! 	      insert_insn_on_edge (
! 			gen_interval_profiler (&cdesc, loop_histograms_label,
! 			profile_info.count_histogram_counters
! 				+ (loop->num - 1) * (histogram_steps + 1)),
! 			e);
! 	    }
  	}
      }
    free (loop_counters);
*************** instrument_loops (loops)
*** 284,289 ****
--- 306,367 ----
    profile_info.count_histogram_counters_now = n_histogram_counters;
    profile_info.count_histogram_counters += n_histogram_counters;
  }
+ 
+ /* Add code to measure histograms of VALUES.  */
+ static void
+ instrument_values (n_values, values)
+      unsigned n_values;
+      struct histogram_value *values;
+ {
+   rtx sequence;
+   unsigned i;
+   edge e;
+   int n_histogram_counters = 0;
+  
+   /* 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:
+ 	  sequence = 
+ 	      gen_interval_profiler (values + i, value_histograms_label,
+ 			profile_info.count_value_counters + n_histogram_counters);
+ 	  break;
+ 
+ 	case HIST_TYPE_RANGE:
+ 	  sequence = 
+ 	      gen_range_profiler (values + i, value_histograms_label,
+ 			profile_info.count_value_counters + n_histogram_counters);
+ 	  break;
+ 
+ 	case HIST_TYPE_POW2:
+ 	  sequence = 
+ 	      gen_pow2_profiler (values + i, value_histograms_label,
+ 			profile_info.count_value_counters + n_histogram_counters);
+ 	  break;
+ 
+ 	case HIST_TYPE_ONE_VALUE:
+ 	  sequence = 
+ 	      gen_one_value_profiler (values + i, value_histograms_label,
+ 			profile_info.count_value_counters + n_histogram_counters);
+ 	  break;
+ 
+ 	default:
+ 	  abort ();
+ 	}
+ 
+       insert_insn_on_edge (sequence, e);
+       n_histogram_counters += values[i].n_counters;
+     }
+ 
+   profile_info.count_value_counters_now = n_histogram_counters;
+   profile_info.count_value_counters += n_histogram_counters;
+ }
  
  struct section_reference
  {
*************** index_counts_file ()
*** 430,438 ****
  	  if (length != GCOV_SUMMARY_LENGTH)
  	    goto corrupt;
  
- 	  if (length != GCOV_SUMMARY_LENGTH)
- 	    goto corrupt;
- 
  	  if (summary)
  	    *summary = offset;
  	  summary = NULL;
--- 508,513 ----
*************** index_counts_file ()
*** 456,462 ****
  		    }
  		  (*slot)->n_offsets++;
  		  (*slot)->offsets = xrealloc ((*slot)->offsets,
! 					       sizeof (long) * (*slot)->n_offsets);
  		}
  	      else
  		{
--- 531,537 ----
  		    }
  		  (*slot)->n_offsets++;
  		  (*slot)->offsets = xrealloc ((*slot)->offsets,
! 					       sizeof (struct section_reference) * (*slot)->n_offsets);
  		}
  	      else
  		{
*************** index_counts_file ()
*** 465,471 ****
  		  (*slot)->section = tag;
  		  (*slot)->checksum = checksum;
  		  (*slot)->n_offsets = 1;
! 		  (*slot)->offsets = xmalloc (sizeof (long));
  		}
  	      (*slot)->offsets[(*slot)->n_offsets - 1].offset = offset;
  	      if (summary)
--- 540,546 ----
  		  (*slot)->section = tag;
  		  (*slot)->checksum = checksum;
  		  (*slot)->n_offsets = 1;
! 		  (*slot)->offsets = xmalloc (sizeof (struct section_reference));
  		}
  	      (*slot)->offsets[(*slot)->n_offsets - 1].offset = offset;
  	      if (summary)
*************** cleanup:;
*** 623,643 ****
  
  /* Get loop histogram counters.  */
  static gcov_type *
! get_histogram_counts (loops, steps)
!      int loops;
!      int steps;
  {
    gcov_type *profile;
-   gcov_type max_count;
    unsigned ix, i, tag, length, num;
    const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl));
    struct da_index_entry *entry, what;
    struct section_reference *act;
    gcov_type count;
-   unsigned n_counters;
- 
-   profile_info.max_counter_in_program = 0;
-   profile_info.count_profiles_merged = 0;
  
    /* No .da file, no execution counts.  */
    if (!da_file)
--- 698,713 ----
  
  /* Get loop histogram counters.  */
  static gcov_type *
! get_histogram_counts (section_tag, n_counters)
!      unsigned section_tag;
!      unsigned n_counters;
  {
    gcov_type *profile;
    unsigned ix, i, tag, length, num;
    const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl));
    struct da_index_entry *entry, what;
    struct section_reference *act;
    gcov_type count;
  
    /* No .da file, no execution counts.  */
    if (!da_file)
*************** get_histogram_counts (loops, steps)
*** 647,660 ****
  
    /* now read and combine all matching profiles.  */
  
-   n_counters = loops * (steps + 1);
    profile = xmalloc (sizeof (gcov_type) * n_counters);
  
    for (ix = 0; ix < n_counters; ix++)
      profile[ix] = 0;
  
    what.function_name = (char *) name;
!   what.section = GCOV_TAG_LOOP_HISTOGRAMS;
    entry = htab_find (counts_file_index, &what);
    if (!entry)
      {
--- 717,729 ----
  
    /* now read and combine all matching profiles.  */
  
    profile = xmalloc (sizeof (gcov_type) * n_counters);
  
    for (ix = 0; ix < n_counters; ix++)
      profile[ix] = 0;
  
    what.function_name = (char *) name;
!   what.section = section_tag;
    entry = htab_find (counts_file_index, &what);
    if (!entry)
      {
*************** get_histogram_counts (loops, steps)
*** 673,684 ****
        act = entry->offsets + i;
  
        /* Read arc counters.  */
-       max_count = 0;
        gcov_resync (da_file, act->offset, 0);
  
        if (gcov_read_unsigned (da_file, &tag)
  	  || gcov_read_unsigned (da_file, &length)
! 	  || tag != GCOV_TAG_LOOP_HISTOGRAMS)
  	{
  	  /* We have already passed through file, so any error means
  	     something is rotten.  */
--- 742,752 ----
        act = entry->offsets + i;
  
        /* Read arc counters.  */
        gcov_resync (da_file, act->offset, 0);
  
        if (gcov_read_unsigned (da_file, &tag)
  	  || gcov_read_unsigned (da_file, &length)
! 	  || tag != section_tag)
  	{
  	  /* We have already passed through file, so any error means
  	     something is rotten.  */
*************** get_histogram_counts (loops, steps)
*** 696,703 ****
  	{
  	  if (gcov_read_counter (da_file, &count))
  	    abort ();
- 	  if (count > max_count)
- 	    max_count = count;
  	  profile[ix] += count;
  	}
      }
--- 764,769 ----
*************** compute_loop_histograms (loops)
*** 723,729 ****
    if (histogram_steps < (unsigned) PARAM_VALUE (PARAM_MAX_UNROLL_TIMES))
      histogram_steps = PARAM_VALUE (PARAM_MAX_UNROLL_TIMES);
  
!   histogram_counts = get_histogram_counts (loops->num - 1, histogram_steps);
    if (!histogram_counts)
      return;
  
--- 789,796 ----
    if (histogram_steps < (unsigned) PARAM_VALUE (PARAM_MAX_UNROLL_TIMES))
      histogram_steps = PARAM_VALUE (PARAM_MAX_UNROLL_TIMES);
  
!   histogram_counts = get_histogram_counts (GCOV_TAG_LOOP_HISTOGRAMS,
! 					   (loops->num - 1) * (histogram_steps + 1));
    if (!histogram_counts)
      return;
  
*************** compute_loop_histograms (loops)
*** 746,751 ****
--- 813,855 ----
    profile_info.have_loop_histograms = 1;
  }
  
+ /* Load value histograms from .da file.  */
+ static void
+ compute_value_histograms (n_values, values)
+      unsigned n_values;
+      struct histogram_value *values;
+ {
+   unsigned i, j, n_histogram_counters;
+   gcov_type *histogram_counts, *act_count;
+   
+   n_histogram_counters = 0;
+   for (i = 0; i < n_values; i++)
+     n_histogram_counters += values[i].n_counters;
+ 
+   histogram_counts = get_histogram_counts (GCOV_TAG_VALUE_HISTOGRAMS,
+ 					   n_histogram_counters);
+   if (!histogram_counts)
+     return;
+ 
+   act_count = histogram_counts;
+   for (i = 0; i < n_values; i++)
+     {
+       rtx hist_list = NULL_RTX;
+ 
+       for (j = values[i].n_counters; j > 0; j--)
+ 	hist_list = alloc_EXPR_LIST (0, GEN_INT (act_count[j - 1]), hist_list);
+       hist_list = alloc_EXPR_LIST (0, copy_rtx (values[i].value), hist_list);
+       hist_list = alloc_EXPR_LIST (0, GEN_INT (values[i].type), hist_list);
+       REG_NOTES (values[i].insn) =
+ 	      alloc_EXPR_LIST (REG_VALUE_HISTOGRAM, hist_list,
+ 			       REG_NOTES (values[i].insn));
+       act_count += values[i].n_counters;
+     }
+ 
+   free (histogram_counts);
+   profile_info.have_value_histograms = 1;
+ }
+ 
  /* Compute the branch probabilities for the various branches.
     Annotate them accordingly.  */
  
*************** branch_prob ()
*** 1123,1133 ****
--- 1227,1240 ----
    int num_edges, ignored_edges;
    struct edge_list *el;
    struct loops loops;
+   unsigned n_values;
+   struct histogram_value *values;
    const char *name = IDENTIFIER_POINTER
  		      (DECL_ASSEMBLER_NAME (current_function_decl));
  
    profile_info.current_function_cfg_checksum = compute_checksum ();
    profile_info.have_loop_histograms = 0;
+   profile_info.have_value_histograms = 0;
  
    if (rtl_dump_file)
      fprintf (rtl_dump_file, "CFG checksum is %u\n",
*************** branch_prob ()
*** 1428,1438 ****
--- 1535,1550 ----
        }
      }
  
+   if (flag_value_histograms)
+     find_values_to_profile (&n_values, &values);
+ 
    if (flag_branch_probabilities)
      {
        compute_branch_probabilities ();
        if (flag_loop_histograms)
  	compute_loop_histograms (&loops);
+       if (flag_value_histograms)
+ 	compute_value_histograms (n_values, values);
      }
  
    /* For each edge not on the spanning tree, add counting code as rtl.  */
*************** branch_prob ()
*** 1445,1451 ****
        if (flag_loop_histograms)
  	instrument_loops (&loops);
  
!       /* Commit changes done by instrument_edges and instrument_loops.  */
        commit_edge_insertions_watch_calls ();
        allocate_reg_info (max_reg_num (), FALSE, FALSE);
  
--- 1557,1566 ----
        if (flag_loop_histograms)
  	instrument_loops (&loops);
  
!       if (flag_value_histograms)
! 	instrument_values (n_values, values);
! 
!       /* Commit changes done by instrumentation.  */
        commit_edge_insertions_watch_calls ();
        allocate_reg_info (max_reg_num (), FALSE, FALSE);
  
*************** branch_prob ()
*** 1460,1465 ****
--- 1575,1581 ----
        item->cfg_checksum = profile_info.current_function_cfg_checksum;
        item->count_edges = profile_info.count_edges_instrumented_now;
        item->histogram_counters = profile_info.count_histogram_counters_now;
+       item->value_counters = profile_info.count_value_counters_now;
      }
  
    if (flag_loop_histograms)
*************** branch_prob ()
*** 1468,1473 ****
--- 1584,1595 ----
        flow_loops_free (&loops);
      }
  
+   if (flag_value_histograms)
+     {
+       /* Free list of interesting values.  */
+       free_profiled_values (n_values, values);
+     }
+ 
    remove_fake_edges ();
    free_aux_for_edges ();
    /* Re-merge split basic blocks and the mess introduced by
*************** init_branch_prob (filename)
*** 1644,1654 ****
        ASM_GENERATE_INTERNAL_LABEL (buf, "LPBX", 2);
        profiler_label = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
  
!       if (flag_loop_histograms)
! 	{
! 	  ASM_GENERATE_INTERNAL_LABEL (buf, "LPBX", 3);
! 	  loop_histograms_label = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
! 	}
      }
    
    total_num_blocks = 0;
--- 1766,1776 ----
        ASM_GENERATE_INTERNAL_LABEL (buf, "LPBX", 2);
        profiler_label = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
  
!       ASM_GENERATE_INTERNAL_LABEL (buf, "LPBX", 3);
!       loop_histograms_label = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
! 
!       ASM_GENERATE_INTERNAL_LABEL (buf, "LPBX", 4);
!       value_histograms_label = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
      }
    
    total_num_blocks = 0;
*************** create_profiler ()
*** 1752,1758 ****
    int save_flag_inline_functions = flag_inline_functions;
  
    if (!profile_info.count_instrumented_edges
!       && !profile_info.count_histogram_counters)
      return;
    
    string_type = build_pointer_type
--- 1874,1881 ----
    int save_flag_inline_functions = flag_inline_functions;
  
    if (!profile_info.count_instrumented_edges
!       && !profile_info.count_histogram_counters
!       && !profile_info.count_value_counters)
      return;
    
    string_type = build_pointer_type
*************** create_profiler ()
*** 1817,1823 ****
      int num_nodes = 0;
      tree array_value = NULL_TREE;
      tree finfo_type, finfo_ptr_type;
!     tree name, checksum, arcs, histogram_counters;
      
      finfo_type = (*lang_hooks.types.make_type) (RECORD_TYPE);
      name = build_decl (FIELD_DECL, NULL_TREE, string_type);
--- 1940,1946 ----
      int num_nodes = 0;
      tree array_value = NULL_TREE;
      tree finfo_type, finfo_ptr_type;
!     tree name, checksum, arcs, histogram_counters, value_counters;
      
      finfo_type = (*lang_hooks.types.make_type) (RECORD_TYPE);
      name = build_decl (FIELD_DECL, NULL_TREE, string_type);
*************** create_profiler ()
*** 1827,1834 ****
      TREE_CHAIN (arcs) = checksum;
      histogram_counters = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
      TREE_CHAIN (histogram_counters) = arcs;
      finish_builtin_struct (finfo_type, "__function_info",
! 			   histogram_counters, NULL_TREE);
      finfo_ptr_type = build_pointer_type
        (build_qualified_type (finfo_type, TYPE_QUAL_CONST));
      
--- 1950,1959 ----
      TREE_CHAIN (arcs) = checksum;
      histogram_counters = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
      TREE_CHAIN (histogram_counters) = arcs;
+     value_counters = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
+     TREE_CHAIN (value_counters) = histogram_counters;
      finish_builtin_struct (finfo_type, "__function_info",
! 			   value_counters, NULL_TREE);
      finfo_ptr_type = build_pointer_type
        (build_qualified_type (finfo_type, TYPE_QUAL_CONST));
      
*************** create_profiler ()
*** 1855,1860 ****
--- 1980,1989 ----
  				 (unsigned_type_node,
  				  build_int_2 (item->histogram_counters, 0)),
  				 finfo_value);
+ 	finfo_value = tree_cons (value_counters, convert
+ 				 (unsigned_type_node,
+ 				  build_int_2 (item->value_counters, 0)),
+ 				 finfo_value);
  	array_value = tree_cons (NULL_TREE, build
  				 (CONSTRUCTOR, finfo_type, NULL_TREE,
  				  nreverse (finfo_value)), array_value);
*************** create_profiler ()
*** 1957,1963 ****
--- 2086,2127 ----
  		      build_int_2 (profile_info
  				   .count_histogram_counters, 0)),
  		     value);
+ 
+   /* value histogram counters table */
+   {
+     tree counts_table = null_pointer_node;
+     
+     if (profile_info.count_value_counters)
+       {
+ 	tree gcov_type_array_type
+ 	  = build_array_type (gcov_type, build_index_type
+ 			      (build_int_2 (profile_info.
+ 					    count_value_counters - 1, 0)));
+ 	/* No values.  */
+ 	counts_table
+ 	  = build (VAR_DECL, gcov_type_array_type, NULL_TREE, NULL_TREE);
+ 	TREE_STATIC (counts_table) = 1;
+ 	DECL_NAME (counts_table) = get_identifier (XSTR (value_histograms_label, 0));
+ 	assemble_variable (counts_table, 0, 0, 0);
+ 	counts_table = build1 (ADDR_EXPR, gcov_ptr_type, counts_table);
+       }
+     
+     field = build_decl (FIELD_DECL, NULL_TREE, gcov_ptr_type);
+     TREE_CHAIN (field) = fields;
+     fields = field;
+     value = tree_cons (fields, counts_table, value);
+   }
    
+   /* number of value histogram counters */
+   field = build_decl (FIELD_DECL, NULL_TREE, unsigned_type_node);
+   TREE_CHAIN (field) = fields;
+   fields = field;
+   value = tree_cons (fields, convert
+ 		     (unsigned_type_node,
+ 		      build_int_2 (profile_info
+ 				   .count_value_counters, 0)),
+ 		     value);
+ 
    finish_builtin_struct (ginfo_type, "__gcov_info", fields, NULL_TREE);
    structure = build (VAR_DECL, ginfo_type, NULL_TREE, NULL_TREE);
    DECL_INITIAL (structure)
*************** gen_edge_profiler (edgeno)
*** 2053,2099 ****
    return sequence;
  }
  
! /* Output instructions as RTL to increment the loop histogram counter.  */
  
  static rtx
! gen_loop_profiler (iterations, loop, steps)
!      rtx iterations;
!      int loop;
!      int steps;
  {
    enum machine_mode mode = mode_for_size (GCOV_TYPE_SIZE, MODE_INT, 0);
!   rtx mem_ref, tmp, tmp1, mr;
    rtx sequence;
!   int base = (loop - 1) * (steps + 1);
!   rtx in_range_label = gen_label_rtx ();
    rtx end_of_code_label = gen_label_rtx ();
    int per_counter = GCOV_TYPE_SIZE / BITS_PER_UNIT;
  
    start_sequence ();
  
    mr = gen_reg_rtx (Pmode);
  
!   tmp = force_reg (Pmode, loop_histograms_label);
!   tmp = plus_constant (tmp,
! 		       per_counter * (base + profile_info.count_histogram_counters));
  
!   do_compare_rtx_and_jump (iterations, GEN_INT (steps), GE, 0, mode, NULL_RTX,
! 			   in_range_label, NULL_RTX);
  
!   tmp1 = expand_simple_binop (Pmode, PLUS, tmp, GEN_INT (per_counter * steps), mr, 0, OPTAB_WIDEN);
    if (tmp1 != mr)
!     emit_move_insn (mr, tmp1);
  
!   emit_jump_insn (gen_jump (end_of_code_label));
!   emit_barrier ();
  
!   emit_label (in_range_label);
  
!   tmp1 = expand_simple_binop (mode, MULT, iterations, GEN_INT (per_counter),
! 			      NULL_RTX, 0, OPTAB_WIDEN);
!   tmp1 = expand_simple_binop (Pmode, PLUS, tmp, tmp1, mr, 0, OPTAB_WIDEN);
!   if (tmp1 != mr)
!     emit_move_insn (mr, tmp1);
  
    emit_label (end_of_code_label);
  
--- 2217,2369 ----
    return sequence;
  }
  
! /* Output instructions as RTL to increment the interval histogram counter.
!    VALUE is the expression whose value is profiled.  BASE_LABEL is the base
!    of histogram counters, BASE is offset from this position.  */
  
  static rtx
! gen_interval_profiler (value, base_label, base)
!      struct histogram_value *value;
!      rtx base_label;
!      int base;
  {
    enum machine_mode mode = mode_for_size (GCOV_TYPE_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_TYPE_SIZE / BITS_PER_UNIT;
  
    start_sequence ();
  
+   if (value->seq)
+     emit_insn (value->seq);
+ 
    mr = gen_reg_rtx (Pmode);
  
!   tmp = force_reg (Pmode, base_label);
!   tmp = plus_constant (tmp, per_counter * base);
  
!   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 range histogram counter.
!    VALUE is the expression whose value is profiled.  BASE_LABEL is the base
!    of histogram counters, BASE is offset from this position.  */
! 
! static rtx
! gen_range_profiler (value, base_label, base)
!      struct histogram_value *value;
!      rtx base_label;
!      int base;
! {
!   enum machine_mode mode = mode_for_size (GCOV_TYPE_SIZE, MODE_INT, 0);
!   rtx mem_ref, tmp, mr, uval;
!   rtx sequence;
!   rtx end_of_code_label = gen_label_rtx ();
!   int per_counter = GCOV_TYPE_SIZE / BITS_PER_UNIT, i;
! 
!   start_sequence ();
! 
!   if (value->seq)
!     emit_insn (value->seq);
! 
!   mr = gen_reg_rtx (Pmode);
! 
!   tmp = force_reg (Pmode, base_label);
!   tmp = plus_constant (tmp, per_counter * base);
!   emit_move_insn (mr, tmp);
! 
!   if (REG_P (value->value))
!     {
!       uval = value->value;
!     }
!   else
!     {
!       uval = gen_reg_rtx (value->mode);
!       emit_move_insn (uval, copy_rtx (value->value));
!     }
! 
!   for (i = 0; i < value->hdata.range.n_ranges; i++)
!     {
!       do_compare_rtx_and_jump (copy_rtx (uval), GEN_INT (value->hdata.range.ranges[i]),
! 			       LT, 0, value->mode, NULL_RTX,
!     			       NULL_RTX, end_of_code_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);
!     }
  
    emit_label (end_of_code_label);
  
*************** gen_loop_profiler (iterations, loop, ste
*** 2111,2114 ****
--- 2381,2540 ----
    return sequence;
  }
  
+ /* Output instructions as RTL to increment the power of two histogram counter.
+    VALUE is the expression whose value is profiled.  BASE_LABEL is the base
+    of histogram counters, BASE is offset from this position.  */
+ 
+ static rtx
+ gen_pow2_profiler (value, base_label, base)
+      struct histogram_value *value;
+      rtx base_label;
+      int base;
+ {
+   enum machine_mode mode = mode_for_size (GCOV_TYPE_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_TYPE_SIZE / BITS_PER_UNIT;
+ 
+   start_sequence ();
+ 
+   if (value->seq)
+     emit_insn (value->seq);
+ 
+   mr = gen_reg_rtx (Pmode);
+   tmp = force_reg (Pmode, base_label);
+   tmp = plus_constant (tmp, per_counter * base);
+   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.  BASE_LABEL is the base
+    of histogram counters, BASE is offset from this position.  */
+ 
+ static rtx
+ gen_one_value_profiler (value, base_label, base)
+      struct histogram_value *value;
+      rtx base_label;
+      int base;
+ {
+   enum machine_mode mode = mode_for_size (GCOV_TYPE_SIZE, MODE_INT, 0);
+   rtx stored_value_ref, counter_ref, all_ref, stored_value, counter, all, tmp, uval;
+   rtx sequence;
+   rtx same_label = gen_label_rtx ();
+   rtx zero_label = gen_label_rtx ();
+   rtx end_of_code_label = gen_label_rtx ();
+   int per_counter = GCOV_TYPE_SIZE / BITS_PER_UNIT;
+ 
+   start_sequence ();
+ 
+   if (value->seq)
+     emit_insn (value->seq);
+ 
+   tmp = force_reg (Pmode, base_label);
+   stored_value = plus_constant (tmp, per_counter * base);
+   counter = plus_constant (stored_value, per_counter);
+   all = plus_constant (counter, per_counter);
+   stored_value_ref = validize_mem (gen_rtx_MEM (mode, stored_value));
+   counter_ref = validize_mem (gen_rtx_MEM (mode, counter));
+   all_ref = validize_mem (gen_rtx_MEM (mode, all));
+ 
+   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_ref), 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_ref), 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_ref), constm1_rtx,
+ 			     counter_ref, 0, OPTAB_WIDEN);
+ 
+   if (tmp != counter_ref)
+     emit_move_insn (copy_rtx (counter_ref), 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_ref), copy_rtx (uval));
+ 
+   emit_label (same_label);
+   /* Increase the counter.  */
+   tmp = expand_simple_binop (mode, PLUS, copy_rtx (counter_ref), const1_rtx,
+ 			     counter_ref, 0, OPTAB_WIDEN);
+ 
+   if (tmp != counter_ref)
+     emit_move_insn (copy_rtx (counter_ref), 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_ref), const1_rtx,
+ 			     all_ref, 0, OPTAB_WIDEN);
+ 
+   if (tmp != all_ref)
+     emit_move_insn (copy_rtx (all_ref), tmp);
+   sequence = get_insns ();
+   end_sequence ();
+   rebuild_jump_labels (sequence);
+   return sequence;
+ }
  #include "gt-profile.h"
Index: profile.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/profile.h,v
retrieving revision 1.3.14.2
diff -c -3 -p -r1.3.14.2 profile.h
*** profile.h	8 Nov 2002 20:47:12 -0000	1.3.14.2
--- profile.h	21 Nov 2002 19:38:33 -0000
*************** struct profile_info
*** 33,38 ****
--- 33,43 ----
  
      int count_histogram_counters;
  
+     /* Used by final, for allocating the proper amount of storage for the
+        value histogram counters.  */
+ 
+     int count_value_counters;
+ 
      /* Used by final, for writing correct # of instrumented edges
         in this function.  */
  
*************** struct profile_info
*** 43,48 ****
--- 48,58 ----
  
      int count_histogram_counters_now;
  
+     /* Used by final, for writing correct # of value histogram counters
+        in this function.  */
+ 
+     int count_value_counters_now;
+ 
      /* Checksum of the cfg. Used for 'identification' of code.
         Used by final.  */
  
*************** struct profile_info
*** 59,64 ****
--- 69,77 ----
  
      /* Do we also have loop histograms?  */
      int have_loop_histograms;
+ 
+     /* And value histograms?  */
+     int have_value_histograms;
    };
  
  extern struct profile_info profile_info;
Index: rtl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/rtl.c,v
retrieving revision 1.117.6.1
diff -c -3 -p -r1.117.6.1 rtl.c
*** rtl.c	16 Oct 2002 16:07:28 -0000	1.117.6.1
--- rtl.c	21 Nov 2002 19:38:33 -0000
*************** const char * const reg_note_name[] =
*** 226,232 ****
    "REG_WAS_0", "REG_RETVAL", "REG_LIBCALL", "REG_NONNEG",
    "REG_NO_CONFLICT", "REG_UNUSED", "REG_CC_SETTER", "REG_CC_USER",
    "REG_LABEL", "REG_DEP_ANTI", "REG_DEP_OUTPUT", "REG_BR_PROB",
!   "REG_EXEC_COUNT", "REG_NOALIAS", "REG_SAVE_AREA", "REG_BR_PRED",
    "REG_FRAME_RELATED_EXPR", "REG_EH_CONTEXT", "REG_EH_REGION",
    "REG_SAVE_NOTE", "REG_MAYBE_DEAD", "REG_NORETURN",
    "REG_NON_LOCAL_GOTO", "REG_SETJMP", "REG_ALWAYS_RETURN",
--- 226,233 ----
    "REG_WAS_0", "REG_RETVAL", "REG_LIBCALL", "REG_NONNEG",
    "REG_NO_CONFLICT", "REG_UNUSED", "REG_CC_SETTER", "REG_CC_USER",
    "REG_LABEL", "REG_DEP_ANTI", "REG_DEP_OUTPUT", "REG_BR_PROB",
!   "REG_EXEC_COUNT", "REG_VALUE_HISTOGRAM", "REG_NOALIAS",
!   "REG_SAVE_AREA", "REG_BR_PRED",
    "REG_FRAME_RELATED_EXPR", "REG_EH_CONTEXT", "REG_EH_REGION",
    "REG_SAVE_NOTE", "REG_MAYBE_DEAD", "REG_NORETURN",
    "REG_NON_LOCAL_GOTO", "REG_SETJMP", "REG_ALWAYS_RETURN",
Index: rtl.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/rtl.h,v
retrieving revision 1.367.2.3
diff -c -3 -p -r1.367.2.3 rtl.h
*** rtl.h	16 Nov 2002 17:32:36 -0000	1.367.2.3
--- rtl.h	21 Nov 2002 19:38:33 -0000
*************** enum reg_note
*** 688,693 ****
--- 688,697 ----
       block was executed.  */
    REG_EXEC_COUNT,
  
+   /* REG_VALUE_HISTOGRAM is attached to an insn before that the contained
+      histogram of a value is measured.  */
+   REG_VALUE_HISTOGRAM,
+ 
    /* Attached to a call insn; indicates that the call is malloc-like and
       that the pointer returned cannot alias anything else.  */
    REG_NOALIAS,
Index: toplev.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/toplev.c,v
retrieving revision 1.668.2.10
diff -c -3 -p -r1.668.2.10 toplev.c
*** toplev.c	16 Nov 2002 17:32:37 -0000	1.668.2.10
--- toplev.c	21 Nov 2002 19:38:34 -0000
*************** Software Foundation, 59 Temple Place - S
*** 73,78 ****
--- 73,79 ----
  #include "cfglayout.h"
  #include "cfgloop.h"
  #include "gcse-globals.h"
+ #include "vpt.h"
  
  #if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
  #include "dwarf2out.h"
*************** enum dump_file_index
*** 234,239 ****
--- 235,241 ----
    DFI_loop,
    DFI_cfg,
    DFI_bp,
+   DFI_vpt,
    DFI_loop2,
    DFI_ce1,
    DFI_tracer,
*************** static struct dump_file_info dump_file[D
*** 284,289 ****
--- 286,292 ----
    { "loop",	'L', 1, 0, 0 },
    { "cfg",	'f', 1, 0, 0 },
    { "bp",	'b', 1, 0, 0 },
+   { "vpt",	'v', 1, 0, 0 },
    { "loop2",	'L', 1, 0, 0 },
    { "ce1",	'C', 1, 0, 0 },
    { "tracer",	'T', 1, 0, 0 },
*************** int flag_branch_probabilities = 0;
*** 392,397 ****
--- 395,406 ----
  /* Nonzero if generating or using histograms for loop iterations.  */
  int flag_loop_histograms = 0;
  
+ /* Nonzero if generating or using value histograms.  */
+ int flag_value_histograms = 0;
+ 
+ /* Nonzero if value histograms should be used to optimize code.  */
+ int flag_value_profile_transformations = 0;
+ 
  /* Nonzero if basic blocks should be reordered.  */
  
  int flag_reorder_blocks = 0;
*************** static const lang_independent_options f_
*** 1125,1130 ****
--- 1134,1143 ----
     N_("Use profiling information for branch probabilities") },
    {"loop-histograms", &flag_loop_histograms, 1,
     N_("Insert code to measure loop histograms and/or use them") },
+   {"value-histograms", &flag_value_histograms, 1,
+    N_("Insert code to measure value histograms and/or use them") },
+   {"value-profile-transformations", &flag_value_profile_transformations, 1,
+    N_("Use value histograms to optimize code") },
    {"profile", &profile_flag, 1,
     N_("Enable basic program profiling code") },
    {"reorder-blocks", &flag_reorder_blocks, 1,
*************** rest_of_compilation (decl)
*** 3032,3040 ****
  	estimate_probability (&loops);
  
        flow_loops_free (&loops);
!       close_dump_file (DFI_bp, print_rtl_with_bb, insns);
        timevar_pop (TV_BRANCH_PROB);
      }
    if (optimize >= 0)
      {
        open_dump_file (DFI_ce1, decl);
--- 3045,3067 ----
  	estimate_probability (&loops);
  
        flow_loops_free (&loops);
!       close_dump_file (DFI_bp, print_rtl_with_bb, get_insns ());
        timevar_pop (TV_BRANCH_PROB);
      }
+ 
+   if (optimize > 0
+       && flag_branch_probabilities
+       && flag_value_histograms
+       && flag_value_profile_transformations)
+     {
+       open_dump_file (DFI_vpt, decl);
+ 
+       if (value_profile_transformations ())
+ 	cleanup_cfg (CLEANUP_EXPENSIVE);
+ 
+       close_dump_file (DFI_vpt, print_rtl_with_bb, get_insns ());
+     }
+ 
    if (optimize >= 0)
      {
        open_dump_file (DFI_ce1, decl);


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