Commit af166e5d by Zdenek Dvorak Committed by Zdenek Dvorak

value-prof.c: New.

	* value-prof.c: New.
	* value-prof.h: New.
	* Makefile.in (value-prof.o): New.
	(LIBGCOV): Add _gcov_merge_single and _gcov_merge_delta
	(profile.o): Add value-prof.h and tree.h dependency.
	* flags.h (flag_profile_values): Declare.
	* gcov-io.h (GCOV_COUNTERS, GCOV_COUNTER_NAMES, GCOV_MERGE_FUNCTIONS):
	Add new counters.
	(GCOV_COUNTER_V_INTERVAL, GCOV_COUNTER_V_POW2, GCOV_COUNTER_V_SINGLE,
	GCOV_COUNTER_V_DELTA): New counter sections.
	(__gcov_merge_single, __gcov_merge_delta): Declare.
	* flow.c (mark_used_regs): Set subregs_of_mode only when the
	structure is initialized.
	* libgcov.c (__gcov_merge_single, __gcov_merge_delta): New functions.
	* profile.c: Include value-prof.h and tree.h.
	(gen_interval_profiler, gen_pow2_profiler, gen_one_value_profiler,
	gen_const_delta_profiler, instrument_values): New static functions.
	(get_exec_counts): Fix comment.
	(branch_prob): Invoke instrument_values.
	* toplev.c (flag_profile_values): New flag.
	* doc/invoke.texi (-fprofile-values): Document.

From-SVN: r68519
parent ff25ef99
2003-06-24 Zdenek Dvorak <rakdver@atrey.karlin.mff.cuni.cz>
2003-06-26 Zdenek Dvorak <rakdver@atrey.karlin.mff.cuni.cz>
* value-prof.c: New.
* value-prof.h: New.
* Makefile.in (value-prof.o): New.
(LIBGCOV): Add _gcov_merge_single and _gcov_merge_delta
(profile.o): Add value-prof.h and tree.h dependency.
* flags.h (flag_profile_values): Declare.
* gcov-io.h (GCOV_COUNTERS, GCOV_COUNTER_NAMES, GCOV_MERGE_FUNCTIONS):
Add new counters.
(GCOV_COUNTER_V_INTERVAL, GCOV_COUNTER_V_POW2, GCOV_COUNTER_V_SINGLE,
GCOV_COUNTER_V_DELTA): New counter sections.
(__gcov_merge_single, __gcov_merge_delta): Declare.
* flow.c (mark_used_regs): Set subregs_of_mode only when the
structure is initialized.
* libgcov.c (__gcov_merge_single, __gcov_merge_delta): New functions.
* profile.c: Include value-prof.h and tree.h.
(gen_interval_profiler, gen_pow2_profiler, gen_one_value_profiler,
gen_const_delta_profiler, instrument_values): New static functions.
(get_exec_counts): Fix comment.
(branch_prob): Invoke instrument_values.
* toplev.c (flag_profile_values): New flag.
* doc/invoke.texi (-fprofile-values): Document.
2003-06-26 Zdenek Dvorak <rakdver@atrey.karlin.mff.cuni.cz>
* Makefile.in (cfgrtl.o): Add expr.h dependency.
* cfgrtl.c: Include expr.h.
......
......@@ -814,7 +814,7 @@ OBJS = alias.o bb-reorder.o bitmap.o builtins.o caller-save.o calls.o \
insn-extract.o insn-opinit.o insn-output.o insn-peep.o insn-recog.o \
integrate.o intl.o jump.o langhooks.o lcm.o lists.o local-alloc.o \
loop.o mbchar.o optabs.o options.o opts.o params.o predict.o \
print-rtl.o print-tree.o \
print-rtl.o print-tree.o value-prof.o \
profile.o ra.o ra-build.o ra-colorize.o ra-debug.o ra-rewrite.o \
real.o recog.o reg-stack.o regclass.o regmove.o regrename.o \
reload.o reload1.o reorg.o resource.o rtl.o rtlanal.o rtl-error.o \
......@@ -854,7 +854,7 @@ STAGESTUFF = *$(objext) insn-flags.h insn-config.h insn-codes.h \
LIB2FUNCS_ST = _eprintf __gcc_bcmp
# Defined in libgcov.c, included only in gcov library
LIBGCOV = _gcov _gcov_merge_add
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 \
......@@ -1636,7 +1636,10 @@ conflict.o : conflict.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(OBSTACK_H)
$(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)
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 \
......
......@@ -191,6 +191,10 @@ extern int profile_flag;
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;
......
......@@ -3842,7 +3842,8 @@ mark_used_regs (pbi, x, cond, insn)
case SUBREG:
#ifdef CANNOT_CHANGE_MODE_CLASS
if (GET_CODE (SUBREG_REG (x)) == REG
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
......@@ -3891,7 +3892,8 @@ mark_used_regs (pbi, x, cond, insn)
|| GET_CODE (testreg) == SUBREG)
{
#ifdef CANNOT_CHANGE_MODE_CLASS
if (GET_CODE (testreg) == SUBREG
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))
......
......@@ -269,13 +269,23 @@ typedef HOST_WIDEST_INT gcov_type;
#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"}
#define GCOV_COUNTER_V_INTERVAL 1 /* Histogram of value inside an interval. */
#define GCOV_COUNTER_V_POW2 2 /* Histogram of exact power2 logarithm
of a value. */
#define GCOV_COUNTER_V_SINGLE 3 /* The most common value of expression. */
#define GCOV_COUNTER_V_DELTA 4 /* 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", "single", "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) \
......@@ -380,6 +390,13 @@ extern void __gcov_flush (void);
/* 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
......
......@@ -63,6 +63,16 @@ void __gcov_merge_add (gcov_type *counters __attribute__ ((unused)),
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>
......@@ -466,4 +476,83 @@ __gcov_merge_add (gcov_type *counters, unsigned n_counters)
}
#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 */
......@@ -60,6 +60,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#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 {
......@@ -105,7 +107,12 @@ static int total_num_branches;
/* 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));
......@@ -158,9 +165,72 @@ instrument_edges (el)
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_SINGLE_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_SINGLE_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.
Sets max_counter_in_program as a side effect. */
/* Computes hybrid profile for all matching entries in da_file. */
static gcov_type *
get_exec_counts ()
......@@ -553,6 +623,8 @@ branch_prob ()
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++;
......@@ -804,6 +876,13 @@ branch_prob ()
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 ();
......@@ -816,11 +895,16 @@ branch_prob ()
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
......@@ -1029,3 +1113,301 @@ gen_edge_profiler (edgeno)
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_SINGLE_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;
}
......@@ -410,6 +410,10 @@ int profile_flag = 0;
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;
......@@ -1184,6 +1188,8 @@ static const lang_independent_options f_options[] =
N_("Create data files needed by gcov") },
{"branch-probabilities", &flag_dummy, 1,
N_("Use profiling information for branch probabilities") },
{"profile-values", &flag_profile_values, 1,
N_("Insert code to profile values of expressions") },
{"profile", &flag_dummy, 1,
N_("Enable basic program profiling code") },
{"reorder-blocks", &flag_dummy, 1,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment