/* Calculate branch probabilities, and basic block execution counts.
Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, 1999,
- 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+ 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
Contributed by James E. Wilson, UC Berkeley/Cygnus Support;
based on some ideas from Dain Samples of UC Berkeley.
Further mangling by Bob Manson, Cygnus Support.
edges must be on the spanning tree. We also attempt to place
EDGE_CRITICAL edges on the spanning tree.
- The auxiliary file generated is <dumpbase>.bbg. The format is
+ The auxiliary files generated are <dumpbase>.gcno (at compile time)
+ and <dumpbase>.gcda (at run time). The format is
described in full in gcov-io.h. */
/* ??? Register allocation should use basic block execution counts to
#include "coverage.h"
#include "value-prof.h"
#include "tree.h"
+#include "cfghooks.h"
+#include "tree-flow.h"
+
+/* Hooks for profiling. */
+static struct profile_hooks* profile_hooks;
+
+/* File for profiling debug output. */
+static inline FILE*
+profile_dump_file (void) {
+ return profile_hooks->profile_dump_file ();
+}
/* Additional information about the edges we need. */
struct edge_info {
/* Forward declarations. */
static void find_spanning_tree (struct edge_list *);
-static rtx gen_edge_profiler (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 (struct edge_list *);
static void instrument_values (unsigned, struct histogram_value *);
static void compute_branch_probabilities (void);
if (!inf->ignore && !inf->on_tree)
{
- rtx edge_profile;
-
if (e->flags & EDGE_ABNORMAL)
abort ();
- if (rtl_dump_file)
- fprintf (rtl_dump_file, "Edge %d to %d instrumented%s\n",
+ if (dump_file)
+ fprintf (dump_file, "Edge %d to %d instrumented%s\n",
e->src->index, e->dest->index,
EDGE_CRITICAL_P (e) ? " (and split)" : "");
- edge_profile = gen_edge_profiler (num_instr_edges++);
- insert_insn_on_edge (edge_profile, e);
- rebuild_jump_labels (e->insns);
+ (profile_hooks->gen_edge_profiler) (num_instr_edges++, e);
}
}
}
total_num_blocks_created += num_edges;
- if (rtl_dump_file)
- fprintf (rtl_dump_file, "%d edges instrumented\n", num_instr_edges);
+ if (dump_file)
+ fprintf (dump_file, "%d edges instrumented\n", num_instr_edges);
return num_instr_edges;
}
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:
switch (values[i].type)
{
case HIST_TYPE_INTERVAL:
- sequence = gen_interval_profiler (values + i, t, 0);
+ (profile_hooks->gen_interval_profiler) (values + i, t, 0);
break;
case HIST_TYPE_POW2:
- sequence = gen_pow2_profiler (values + i, t, 0);
+ (profile_hooks->gen_pow2_profiler) (values + i, t, 0);
break;
case HIST_TYPE_SINGLE_VALUE:
- sequence = gen_one_value_profiler (values + i, t, 0);
+ (profile_hooks->gen_one_value_profiler) (values + i, t, 0);
break;
case HIST_TYPE_CONST_DELTA:
- sequence = gen_const_delta_profiler (values + i, t, 0);
+ (profile_hooks->gen_const_delta_profiler) (values + i, t, 0);
break;
default:
abort ();
}
-
- safe_insert_insn_on_edge (sequence, e);
}
}
\f
if (!counts)
return NULL;
- if (rtl_dump_file && profile_info)
- fprintf(rtl_dump_file, "Merged %u profiles with maximal count %u.\n",
+ if (dump_file && profile_info)
+ fprintf(dump_file, "Merged %u profiles with maximal count %u.\n",
profile_info->runs, (unsigned) profile_info->sum_max);
return counts;
EDGE_INFO (e)->count_valid = 1;
BB_INFO (bb)->succ_count--;
BB_INFO (e->dest)->pred_count--;
- if (rtl_dump_file)
+ if (dump_file)
{
- fprintf (rtl_dump_file, "\nRead edge from %i to %i, count:",
+ fprintf (dump_file, "\nRead edge from %i to %i, count:",
bb->index, e->dest->index);
- fprintf (rtl_dump_file, HOST_WIDEST_INT_PRINT_DEC,
+ fprintf (dump_file, HOST_WIDEST_INT_PRINT_DEC,
(HOST_WIDEST_INT) e->count);
}
}
}
- if (rtl_dump_file)
- fprintf (rtl_dump_file, "\n%d edge counts read\n", num_edges);
+ if (dump_file)
+ fprintf (dump_file, "\n%d edge counts read\n", num_edges);
/* For every block in the file,
- if every exit/entrance edge has a known count, then set the block count
}
}
}
- if (rtl_dump_file)
- dump_flow_info (rtl_dump_file);
+ if (dump_file)
+ dump_flow_info (dump_file);
total_num_passes += passes;
- if (rtl_dump_file)
- fprintf (rtl_dump_file, "Graph solving took %d passes.\n\n", passes);
+ if (dump_file)
+ fprintf (dump_file, "Graph solving took %d passes.\n\n", passes);
/* If the graph has been correctly solved, every block will have a
succ and pred count of zero. */
|| (e->count > bb->count
&& e->dest != EXIT_BLOCK_PTR))
{
- rtx insn = BB_END (bb);
-
- while (GET_CODE (insn) != CALL_INSN
- && insn != BB_HEAD (bb)
- && keep_with_call_p (insn))
- insn = PREV_INSN (insn);
- if (GET_CODE (insn) == CALL_INSN)
+ if (block_ends_with_call_p (bb))
e->count = e->count < 0 ? 0 : bb->count;
}
if (e->count < 0 || e->count > bb->count)
for (e = bb->succ; e; e = e->succ_next)
e->probability = (e->count * REG_BR_PROB_BASE + bb->count / 2) / bb->count;
if (bb->index >= 0
- && any_condjump_p (BB_END (bb))
+ && block_ends_with_condjump_p (bb)
&& bb->succ->succ_next)
{
int prob;
index = 19;
hist_br_prob[index]++;
- note = find_reg_note (BB_END (bb), REG_BR_PROB, 0);
- /* There may be already note put by some other pass, such
- as builtin_expect expander. */
- if (note)
- XEXP (note, 0) = GEN_INT (prob);
- else
- REG_NOTES (BB_END (bb))
- = gen_rtx_EXPR_LIST (REG_BR_PROB, GEN_INT (prob),
- REG_NOTES (BB_END (bb)));
+ /* Do this for RTL only. */
+ if (!ir_type ())
+ {
+ note = find_reg_note (BB_END (bb), REG_BR_PROB, 0);
+ /* There may be already note put by some other pass, such
+ as builtin_expect expander. */
+ if (note)
+ XEXP (note, 0) = GEN_INT (prob);
+ else
+ REG_NOTES (BB_END (bb))
+ = gen_rtx_EXPR_LIST (REG_BR_PROB, GEN_INT (prob),
+ REG_NOTES (BB_END (bb)));
+ }
num_branches++;
}
}
e->probability = REG_BR_PROB_BASE / total;
}
if (bb->index >= 0
- && any_condjump_p (BB_END (bb))
+ && block_ends_with_condjump_p (bb)
&& bb->succ->succ_next)
num_branches++, num_never_executed;
}
}
- if (rtl_dump_file)
+ if (dump_file)
{
- fprintf (rtl_dump_file, "%d branches\n", num_branches);
- fprintf (rtl_dump_file, "%d branches never executed\n",
+ fprintf (dump_file, "%d branches\n", num_branches);
+ fprintf (dump_file, "%d branches never executed\n",
num_never_executed);
if (num_branches)
for (i = 0; i < 10; i++)
- fprintf (rtl_dump_file, "%d%% branches in range %d-%d%%\n",
+ fprintf (dump_file, "%d%% branches in range %d-%d%%\n",
(hist_br_prob[i] + hist_br_prob[19-i]) * 100 / num_branches,
5 * i, 5 * i + 5);
for (i = 0; i < 20; i++)
total_hist_br_prob[i] += hist_br_prob[i];
- fputc ('\n', rtl_dump_file);
- fputc ('\n', rtl_dump_file);
+ fputc ('\n', dump_file);
+ fputc ('\n', dump_file);
}
free_aux_for_blocks ();
rtx hist_list = NULL_RTX;
t = (int) (values[i].type);
- aact_count = act_count[t];
- act_count[t] += values[i].n_counters;
- for (j = values[i].n_counters; j > 0; j--)
- hist_list = alloc_EXPR_LIST (0, GEN_INT (aact_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_PROFILE, hist_list,
- REG_NOTES (values[i].insn));
+ /* FIXME: make this work for trees. */
+ if (!ir_type ())
+ {
+ aact_count = act_count[t];
+ act_count[t] += values[i].n_counters;
+ for (j = values[i].n_counters; j > 0; j--)
+ hist_list = alloc_EXPR_LIST (0, GEN_INT (aact_count[j - 1]),
+ hist_list);
+ hist_list = alloc_EXPR_LIST (0,
+ copy_rtx ((rtx)values[i].value), hist_list);
+ hist_list = alloc_EXPR_LIST (0, GEN_INT (values[i].type), hist_list);
+ REG_NOTES ((rtx)values[i].insn) =
+ alloc_EXPR_LIST (REG_VALUE_PROFILE, hist_list,
+ REG_NOTES ((rtx)values[i].insn));
+ }
}
for (t = 0; t < GCOV_N_VALUE_COUNTERS; t++)
if (need_exit_edge && !have_exit_edge)
{
- if (rtl_dump_file)
- fprintf (rtl_dump_file, "Adding fake exit edge to bb %i\n",
+ if (dump_file)
+ fprintf (dump_file, "Adding fake exit edge to bb %i\n",
bb->index);
make_edge (bb, EXIT_BLOCK_PTR, EDGE_FAKE);
}
if (need_entry_edge && !have_entry_edge)
{
- if (rtl_dump_file)
- fprintf (rtl_dump_file, "Adding fake entry edge to bb %i\n",
+ if (dump_file)
+ fprintf (dump_file, "Adding fake entry edge to bb %i\n",
bb->index);
make_edge (ENTRY_BLOCK_PTR, bb, EDGE_FAKE);
}
}
total_num_blocks += n_basic_blocks + 2;
- if (rtl_dump_file)
- fprintf (rtl_dump_file, "%d basic blocks\n", n_basic_blocks);
+ if (dump_file)
+ fprintf (dump_file, "%d basic blocks\n", n_basic_blocks);
total_num_edges += num_edges;
- if (rtl_dump_file)
- fprintf (rtl_dump_file, "%d edges\n", num_edges);
+ if (dump_file)
+ fprintf (dump_file, "%d edges\n", num_edges);
total_num_edges_ignored += ignored_edges;
- if (rtl_dump_file)
- fprintf (rtl_dump_file, "%d ignored edges\n", ignored_edges);
+ if (dump_file)
+ fprintf (dump_file, "%d ignored edges\n", ignored_edges);
/* Write the data from which gcov can reconstruct the basic block
graph. */
}
/* Line numbers. */
- if (coverage_begin_output ())
+ /* FIXME: make this work for trees. (Line numbers are in location_t
+ objects, but aren't always attached to the obvious tree...) */
+ if (coverage_begin_output () && !ir_type ())
{
char const *prev_file_name = NULL;
gcov_position_t offset;
}
}
}
+
ENTRY_BLOCK_PTR->index = ENTRY_BLOCK;
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);
- }
+ find_values_to_profile (&n_values, &values);
if (flag_branch_probabilities)
{
compute_value_histograms (n_values, values);
}
- /* For each edge not on the spanning tree, add counting code as rtl. */
+ /* For each edge not on the spanning tree, add counting code. */
if (profile_arc_flag
&& coverage_counter_alloc (GCOV_COUNTER_ARCS, num_instrumented))
{
instrument_values (n_values, values);
/* Commit changes done by instrumentation. */
- commit_edge_insertions_watch_calls ();
- allocate_reg_info (max_reg_num (), FALSE, FALSE);
+ if (ir_type ())
+ bsi_commit_edge_inserts ((int *)NULL);
+ else
+ {
+ commit_edge_insertions_watch_calls ();
+ allocate_reg_info (max_reg_num (), FALSE, FALSE);
+ }
}
remove_fake_edges ();
free_aux_for_edges ();
- /* Re-merge split basic blocks and the mess introduced by
- insert_insn_on_edge. */
- cleanup_cfg (profile_arc_flag ? CLEANUP_EXPENSIVE : 0);
- if (rtl_dump_file)
- dump_flow_info (rtl_dump_file);
+
+ if (!ir_type ())
+ {
+ /* Re-merge split basic blocks and the mess introduced by
+ insert_insn_on_edge. */
+ cleanup_cfg (profile_arc_flag ? CLEANUP_EXPENSIVE : 0);
+ if (profile_dump_file())
+ dump_flow_info (profile_dump_file());
+ }
free_edge_list (el);
}
&& !EDGE_INFO (e)->ignore
&& (find_group (e->src) != find_group (e->dest)))
{
- if (rtl_dump_file)
- fprintf (rtl_dump_file, "Abnormal edge %d to %d put to tree\n",
+ if (dump_file)
+ fprintf (dump_file, "Abnormal edge %d to %d put to tree\n",
e->src->index, e->dest->index);
EDGE_INFO (e)->on_tree = 1;
union_groups (e->src, e->dest);
if (EDGE_CRITICAL_P (e) && !EDGE_INFO (e)->ignore
&& find_group (e->src) != find_group (e->dest))
{
- if (rtl_dump_file)
- fprintf (rtl_dump_file, "Critical edge %d to %d put to tree\n",
+ if (dump_file)
+ fprintf (dump_file, "Critical edge %d to %d put to tree\n",
e->src->index, e->dest->index);
EDGE_INFO (e)->on_tree = 1;
union_groups (e->src, e->dest);
if (!EDGE_INFO (e)->ignore
&& find_group (e->src) != find_group (e->dest))
{
- if (rtl_dump_file)
- fprintf (rtl_dump_file, "Normal edge %d to %d put to tree\n",
+ if (dump_file)
+ fprintf (dump_file, "Normal edge %d to %d put to tree\n",
e->src->index, e->dest->index);
EDGE_INFO (e)->on_tree = 1;
union_groups (e->src, e->dest);
void
end_branch_prob (void)
{
- if (rtl_dump_file)
+ if (dump_file)
{
- fprintf (rtl_dump_file, "\n");
- fprintf (rtl_dump_file, "Total number of blocks: %d\n",
+ fprintf (dump_file, "\n");
+ fprintf (dump_file, "Total number of blocks: %d\n",
total_num_blocks);
- fprintf (rtl_dump_file, "Total number of edges: %d\n", total_num_edges);
- fprintf (rtl_dump_file, "Total number of ignored edges: %d\n",
+ fprintf (dump_file, "Total number of edges: %d\n", total_num_edges);
+ fprintf (dump_file, "Total number of ignored edges: %d\n",
total_num_edges_ignored);
- fprintf (rtl_dump_file, "Total number of instrumented edges: %d\n",
+ fprintf (dump_file, "Total number of instrumented edges: %d\n",
total_num_edges_instrumented);
- fprintf (rtl_dump_file, "Total number of blocks created: %d\n",
+ fprintf (dump_file, "Total number of blocks created: %d\n",
total_num_blocks_created);
- fprintf (rtl_dump_file, "Total number of graph solution passes: %d\n",
+ fprintf (dump_file, "Total number of graph solution passes: %d\n",
total_num_passes);
if (total_num_times_called != 0)
- fprintf (rtl_dump_file, "Average number of graph solution passes: %d\n",
+ fprintf (dump_file, "Average number of graph solution passes: %d\n",
(total_num_passes + (total_num_times_called >> 1))
/ total_num_times_called);
- fprintf (rtl_dump_file, "Total number of branches: %d\n",
+ fprintf (dump_file, "Total number of branches: %d\n",
total_num_branches);
- fprintf (rtl_dump_file, "Total number of branches never executed: %d\n",
+ fprintf (dump_file, "Total number of branches never executed: %d\n",
total_num_never_executed);
if (total_num_branches)
{
int i;
for (i = 0; i < 10; i++)
- fprintf (rtl_dump_file, "%d%% branches in range %d-%d%%\n",
+ fprintf (dump_file, "%d%% branches in range %d-%d%%\n",
(total_hist_br_prob[i] + total_hist_br_prob[19-i]) * 100
/ total_num_branches, 5*i, 5*i+5);
}
}
}
-\f
-/* Output instructions as RTL to increment the edge execution count. */
-
-static rtx
-gen_edge_profiler (int edgeno)
-{
- rtx ref = coverage_counter_ref (GCOV_COUNTER_ARCS, edgeno);
- rtx tmp;
- enum machine_mode mode = GET_MODE (ref);
- rtx sequence;
-
- start_sequence ();
- ref = validize_mem (ref);
-
- tmp = expand_simple_binop (mode, PLUS, ref, const1_rtx,
- ref, 0, OPTAB_WIDEN);
-
- if (tmp != ref)
- emit_move_insn (copy_rtx (ref), tmp);
-
- 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. */
+/* Set up hooks to enable tree-based profiling. */
-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)
+void
+tree_register_profile_hooks (void)
{
- 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;
+ profile_hooks = &tree_profile_hooks;
+ if (!ir_type ())
+ abort ();
}
-/* 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. */
+/* Set up hooks to enable RTL-based profiling. */
-static rtx
-gen_const_delta_profiler (struct histogram_value *value, unsigned tag,
- unsigned base)
+void
+rtl_register_profile_hooks (void)
{
- 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;
+ profile_hooks = &rtl_profile_hooks;
+ if (ir_type ())
+ abort ();
}