#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "rtl.h"
#include "flags.h"
#include "output.h"
#include "regs.h"
#include "expr.h"
#include "function.h"
#include "toplev.h"
#include "coverage.h"
#include "value-prof.h"
#include "tree.h"
#include "cfghooks.h"
#include "tree-flow.h"
static struct profile_hooks* profile_hooks;
static inline FILE*
profile_dump_file (void) {
return profile_hooks->profile_dump_file ();
}
struct edge_info {
unsigned int count_valid : 1;
unsigned int on_tree : 1;
unsigned int ignore : 1;
};
struct bb_info {
unsigned int count_valid : 1;
gcov_type succ_count;
gcov_type pred_count;
};
#define EDGE_INFO(e) ((struct edge_info *) (e)->aux)
#define BB_INFO(b) ((struct bb_info *) (b)->aux)
const struct gcov_ctr_summary *profile_info;
static int total_num_blocks;
static int total_num_edges;
static int total_num_edges_ignored;
static int total_num_edges_instrumented;
static int total_num_blocks_created;
static int total_num_passes;
static int total_num_times_called;
static int total_hist_br_prob[20];
static int total_num_never_executed;
static int total_num_branches;
static void find_spanning_tree (struct edge_list *);
static unsigned instrument_edges (struct edge_list *);
static void instrument_values (unsigned, struct histogram_value *);
static void compute_branch_probabilities (void);
static void compute_value_histograms (unsigned, struct histogram_value *);
static gcov_type * get_exec_counts (void);
static basic_block find_group (basic_block);
static void union_groups (basic_block, basic_block);
static unsigned
instrument_edges (struct edge_list *el)
{
unsigned num_instr_edges = 0;
int num_edges = NUM_EDGES (el);
basic_block bb;
remove_fake_edges ();
FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
{
edge e;
for (e = bb->succ; e; e = e->succ_next)
{
struct edge_info *inf = EDGE_INFO (e);
if (!inf->ignore && !inf->on_tree)
{
if (e->flags & EDGE_ABNORMAL)
abort ();
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)" : "");
(profile_hooks->gen_edge_profiler) (num_instr_edges++, e);
}
}
}
total_num_blocks_created += num_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)
{
unsigned i, t;
for (i = 0; i < n_values; i++)
{
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:
(profile_hooks->gen_interval_profiler) (values + i, t, 0);
break;
case HIST_TYPE_POW2:
(profile_hooks->gen_pow2_profiler) (values + i, t, 0);
break;
case HIST_TYPE_SINGLE_VALUE:
(profile_hooks->gen_one_value_profiler) (values + i, t, 0);
break;
case HIST_TYPE_CONST_DELTA:
(profile_hooks->gen_const_delta_profiler) (values + i, t, 0);
break;
default:
abort ();
}
}
}
static gcov_type *
get_exec_counts (void)
{
unsigned num_edges = 0;
basic_block bb;
gcov_type *counts;
FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
{
edge e;
for (e = bb->succ; e; e = e->succ_next)
if (!EDGE_INFO (e)->ignore && !EDGE_INFO (e)->on_tree)
num_edges++;
}
counts = get_coverage_counts (GCOV_COUNTER_ARCS, num_edges, &profile_info);
if (!counts)
return NULL;
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;
}
static void
compute_branch_probabilities (void)
{
basic_block bb;
int i;
int num_edges = 0;
int changes;
int passes;
int hist_br_prob[20];
int num_never_executed;
int num_branches;
gcov_type *exec_counts = get_exec_counts ();
int exec_counts_pos = 0;
if (profile_info)
{
if (profile_info->run_max * profile_info->runs < profile_info->sum_max)
{
error ("corrupted profile info: run_max * runs < sum_max");
exec_counts = NULL;
}
if (profile_info->sum_all < profile_info->sum_max)
{
error ("corrupted profile info: sum_all is smaller than sum_max");
exec_counts = NULL;
}
}
alloc_aux_for_blocks (sizeof (struct bb_info));
FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
{
edge e;
for (e = bb->succ; e; e = e->succ_next)
if (!EDGE_INFO (e)->ignore)
BB_INFO (bb)->succ_count++;
for (e = bb->pred; e; e = e->pred_next)
if (!EDGE_INFO (e)->ignore)
BB_INFO (bb)->pred_count++;
}
BB_INFO (EXIT_BLOCK_PTR)->succ_count = 2;
BB_INFO (ENTRY_BLOCK_PTR)->pred_count = 2;
FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
{
edge e;
for (e = bb->succ; e; e = e->succ_next)
if (!EDGE_INFO (e)->ignore && !EDGE_INFO (e)->on_tree)
{
num_edges++;
if (exec_counts)
{
e->count = exec_counts[exec_counts_pos++];
if (e->count > profile_info->sum_max)
{
error ("corrupted profile info: edge from %i to %i exceeds maximal count",
bb->index, e->dest->index);
}
}
else
e->count = 0;
EDGE_INFO (e)->count_valid = 1;
BB_INFO (bb)->succ_count--;
BB_INFO (e->dest)->pred_count--;
if (dump_file)
{
fprintf (dump_file, "\nRead edge from %i to %i, count:",
bb->index, e->dest->index);
fprintf (dump_file, HOST_WIDEST_INT_PRINT_DEC,
(HOST_WIDEST_INT) e->count);
}
}
}
if (dump_file)
fprintf (dump_file, "\n%d edge counts read\n", num_edges);
changes = 1;
passes = 0;
while (changes)
{
passes++;
changes = 0;
FOR_BB_BETWEEN (bb, EXIT_BLOCK_PTR, NULL, prev_bb)
{
struct bb_info *bi = BB_INFO (bb);
if (! bi->count_valid)
{
if (bi->succ_count == 0)
{
edge e;
gcov_type total = 0;
for (e = bb->succ; e; e = e->succ_next)
total += e->count;
bb->count = total;
bi->count_valid = 1;
changes = 1;
}
else if (bi->pred_count == 0)
{
edge e;
gcov_type total = 0;
for (e = bb->pred; e; e = e->pred_next)
total += e->count;
bb->count = total;
bi->count_valid = 1;
changes = 1;
}
}
if (bi->count_valid)
{
if (bi->succ_count == 1)
{
edge e;
gcov_type total = 0;
for (e = bb->succ; e; e = e->succ_next)
total += e->count;
for (e = bb->succ; e; e = e->succ_next)
if (! EDGE_INFO (e)->count_valid && ! EDGE_INFO (e)->ignore)
break;
total = bb->count - total;
if (! e)
abort ();
EDGE_INFO (e)->count_valid = 1;
e->count = total;
bi->succ_count--;
BB_INFO (e->dest)->pred_count--;
changes = 1;
}
if (bi->pred_count == 1)
{
edge e;
gcov_type total = 0;
for (e = bb->pred; e; e = e->pred_next)
total += e->count;
for (e = bb->pred; e; e = e->pred_next)
if (!EDGE_INFO (e)->count_valid && !EDGE_INFO (e)->ignore)
break;
total = bb->count - total + e->count;
if (! e)
abort ();
EDGE_INFO (e)->count_valid = 1;
e->count = total;
bi->pred_count--;
BB_INFO (e->src)->succ_count--;
changes = 1;
}
}
}
}
if (dump_file)
dump_flow_info (dump_file);
total_num_passes += passes;
if (dump_file)
fprintf (dump_file, "Graph solving took %d passes.\n\n", passes);
FOR_EACH_BB (bb)
{
if (BB_INFO (bb)->succ_count || BB_INFO (bb)->pred_count)
abort ();
}
for (i = 0; i < 20; i++)
hist_br_prob[i] = 0;
num_never_executed = 0;
num_branches = 0;
FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
{
edge e;
rtx note;
if (bb->count < 0)
{
error ("corrupted profile info: number of iterations for basic block %d thought to be %i",
bb->index, (int)bb->count);
bb->count = 0;
}
for (e = bb->succ; e; e = e->succ_next)
{
if ((e->count < 0
&& e->dest == EXIT_BLOCK_PTR)
|| (e->count > bb->count
&& e->dest != EXIT_BLOCK_PTR))
{
if (block_ends_with_call_p (bb))
e->count = e->count < 0 ? 0 : bb->count;
}
if (e->count < 0 || e->count > bb->count)
{
error ("corrupted profile info: number of executions for edge %d-%d thought to be %i",
e->src->index, e->dest->index,
(int)e->count);
e->count = bb->count / 2;
}
}
if (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
&& block_ends_with_condjump_p (bb)
&& bb->succ->succ_next)
{
int prob;
edge e;
int index;
for (e = bb->succ; e->flags & (EDGE_FAKE | EDGE_FALLTHRU);
e = e->succ_next)
continue;
prob = e->probability;
index = prob * 20 / REG_BR_PROB_BASE;
if (index == 20)
index = 19;
hist_br_prob[index]++;
if (!ir_type ())
{
note = find_reg_note (BB_END (bb), REG_BR_PROB, 0);
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++;
}
}
else
{
int total = 0;
for (e = bb->succ; e; e = e->succ_next)
if (!(e->flags & (EDGE_COMPLEX | EDGE_FAKE)))
total ++;
if (total)
{
for (e = bb->succ; e; e = e->succ_next)
if (!(e->flags & (EDGE_COMPLEX | EDGE_FAKE)))
e->probability = REG_BR_PROB_BASE / total;
else
e->probability = 0;
}
else
{
for (e = bb->succ; e; e = e->succ_next)
total ++;
for (e = bb->succ; e; e = e->succ_next)
e->probability = REG_BR_PROB_BASE / total;
}
if (bb->index >= 0
&& block_ends_with_condjump_p (bb)
&& bb->succ->succ_next)
num_branches++, num_never_executed;
}
}
if (dump_file)
{
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 (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);
total_num_branches += num_branches;
total_num_never_executed += num_never_executed;
for (i = 0; i < 20; i++)
total_hist_br_prob[i] += hist_br_prob[i];
fputc ('\n', dump_file);
fputc ('\n', dump_file);
}
free_aux_for_blocks ();
}
static void
compute_value_histograms (unsigned n_values, struct histogram_value *values)
{
unsigned i, j, t, any;
unsigned n_histogram_counters[GCOV_N_VALUE_COUNTERS];
gcov_type *histogram_counts[GCOV_N_VALUE_COUNTERS];
gcov_type *act_count[GCOV_N_VALUE_COUNTERS];
gcov_type *aact_count;
for (t = 0; t < GCOV_N_VALUE_COUNTERS; t++)
n_histogram_counters[t] = 0;
for (i = 0; i < n_values; i++)
n_histogram_counters[(int) (values[i].type)] += values[i].n_counters;
any = 0;
for (t = 0; t < GCOV_N_VALUE_COUNTERS; t++)
{
if (!n_histogram_counters[t])
{
histogram_counts[t] = NULL;
continue;
}
histogram_counts[t] =
get_coverage_counts (COUNTER_FOR_HIST_TYPE (t),
n_histogram_counters[t], NULL);
if (histogram_counts[t])
any = 1;
act_count[t] = histogram_counts[t];
}
if (!any)
return;
for (i = 0; i < n_values; i++)
{
rtx hist_list = NULL_RTX;
t = (int) (values[i].type);
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 (histogram_counts[t])
free (histogram_counts[t]);
}
void
branch_prob (void)
{
basic_block bb;
unsigned i;
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++;
flow_call_edges_add (NULL);
add_noreturn_fake_exit_edges ();
FOR_EACH_BB (bb)
{
int need_exit_edge = 0, need_entry_edge = 0;
int have_exit_edge = 0, have_entry_edge = 0;
edge e;
for (e = bb->succ; e; e = e->succ_next)
{
if ((e->flags & (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL))
&& e->dest != EXIT_BLOCK_PTR)
need_exit_edge = 1;
if (e->dest == EXIT_BLOCK_PTR)
have_exit_edge = 1;
}
for (e = bb->pred; e; e = e->pred_next)
{
if ((e->flags & (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL))
&& e->src != ENTRY_BLOCK_PTR)
need_entry_edge = 1;
if (e->src == ENTRY_BLOCK_PTR)
have_entry_edge = 1;
}
if (need_exit_edge && !have_exit_edge)
{
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 (dump_file)
fprintf (dump_file, "Adding fake entry edge to bb %i\n",
bb->index);
make_edge (ENTRY_BLOCK_PTR, bb, EDGE_FAKE);
}
}
el = create_edge_list ();
num_edges = NUM_EDGES (el);
alloc_aux_for_edges (sizeof (struct edge_info));
compact_blocks ();
ignored_edges = 0;
for (i = 0 ; i < num_edges ; i++)
{
edge e = INDEX_EDGE (el, i);
e->count = 0;
if ((e->flags & (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL))
&& e->src != ENTRY_BLOCK_PTR && e->dest != EXIT_BLOCK_PTR)
{
EDGE_INFO (e)->ignore = 1;
ignored_edges++;
}
}
#ifdef ENABLE_CHECKING
verify_flow_info ();
#endif
find_spanning_tree (el);
for (num_instrumented = i = 0; i < num_edges; i++)
{
edge e = INDEX_EDGE (el, i);
struct edge_info *inf = EDGE_INFO (e);
if (inf->ignore || inf->on_tree)
;
else if (e->flags & EDGE_FAKE)
{
inf->ignore = 1;
ignored_edges++;
}
else
num_instrumented++;
}
total_num_blocks += n_basic_blocks + 2;
if (dump_file)
fprintf (dump_file, "%d basic blocks\n", n_basic_blocks);
total_num_edges += num_edges;
if (dump_file)
fprintf (dump_file, "%d edges\n", num_edges);
total_num_edges_ignored += ignored_edges;
if (dump_file)
fprintf (dump_file, "%d ignored edges\n", ignored_edges);
if (coverage_begin_output ())
{
gcov_position_t offset;
offset = gcov_write_tag (GCOV_TAG_BLOCKS);
for (i = 0; i != (unsigned) (n_basic_blocks + 2); i++)
gcov_write_unsigned (0);
gcov_write_length (offset);
}
ENTRY_BLOCK_PTR->index = -1;
EXIT_BLOCK_PTR->index = last_basic_block;
#define BB_TO_GCOV_INDEX(bb) ((bb)->index + 1)
if (coverage_begin_output ())
{
gcov_position_t offset;
FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb)
{
edge e;
offset = gcov_write_tag (GCOV_TAG_ARCS);
gcov_write_unsigned (BB_TO_GCOV_INDEX (bb));
for (e = bb->succ; e; e = e->succ_next)
{
struct edge_info *i = EDGE_INFO (e);
if (!i->ignore)
{
unsigned flag_bits = 0;
if (i->on_tree)
flag_bits |= GCOV_ARC_ON_TREE;
if (e->flags & EDGE_FAKE)
flag_bits |= GCOV_ARC_FAKE;
if (e->flags & EDGE_FALLTHRU)
flag_bits |= GCOV_ARC_FALLTHROUGH;
gcov_write_unsigned (BB_TO_GCOV_INDEX (e->dest));
gcov_write_unsigned (flag_bits);
}
}
gcov_write_length (offset);
}
}
if (coverage_begin_output () && !ir_type ())
{
char const *prev_file_name = NULL;
gcov_position_t offset;
FOR_EACH_BB (bb)
{
rtx insn = BB_HEAD (bb);
int ignore_next_note = 0;
offset = 0;
insn = prev_nonnote_insn (insn);
if (!insn)
insn = get_insns ();
else
insn = NEXT_INSN (insn);
while (insn != BB_END (bb))
{
if (GET_CODE (insn) == NOTE)
{
if (NOTE_LINE_NUMBER (insn)
== NOTE_INSN_REPEATED_LINE_NUMBER)
ignore_next_note = 1;
else if (NOTE_LINE_NUMBER (insn) <= 0)
;
else if (ignore_next_note)
ignore_next_note = 0;
else
{
if (!offset)
{
offset = gcov_write_tag (GCOV_TAG_LINES);
gcov_write_unsigned (BB_TO_GCOV_INDEX (bb));
}
if (!prev_file_name
|| strcmp (NOTE_SOURCE_FILE (insn),
prev_file_name))
{
prev_file_name = NOTE_SOURCE_FILE (insn);
gcov_write_unsigned (0);
gcov_write_string (prev_file_name);
}
gcov_write_unsigned (NOTE_LINE_NUMBER (insn));
}
}
insn = NEXT_INSN (insn);
}
if (offset)
{
gcov_write_unsigned (0);
gcov_write_string (NULL);
gcov_write_length (offset);
}
}
}
ENTRY_BLOCK_PTR->index = ENTRY_BLOCK;
EXIT_BLOCK_PTR->index = EXIT_BLOCK;
#undef BB_TO_GCOV_INDEX
if (flag_profile_values)
find_values_to_profile (&n_values, &values);
if (flag_branch_probabilities)
{
compute_branch_probabilities ();
if (flag_profile_values)
compute_value_histograms (n_values, values);
}
if (profile_arc_flag
&& coverage_counter_alloc (GCOV_COUNTER_ARCS, num_instrumented))
{
unsigned n_instrumented = instrument_edges (el);
if (n_instrumented != num_instrumented)
abort ();
if (flag_profile_values)
instrument_values (n_values, values);
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 ();
if (!ir_type ())
{
cleanup_cfg (profile_arc_flag ? CLEANUP_EXPENSIVE : 0);
if (profile_dump_file())
dump_flow_info (profile_dump_file());
}
free_edge_list (el);
}
static basic_block
find_group (basic_block bb)
{
basic_block group = bb, bb1;
while ((basic_block) group->aux != group)
group = (basic_block) group->aux;
while ((basic_block) bb->aux != group)
{
bb1 = (basic_block) bb->aux;
bb->aux = (void *) group;
bb = bb1;
}
return group;
}
static void
union_groups (basic_block bb1, basic_block bb2)
{
basic_block bb1g = find_group (bb1);
basic_block bb2g = find_group (bb2);
if (bb1g == bb2g)
abort ();
bb1g->aux = bb2g;
}
static void
find_spanning_tree (struct edge_list *el)
{
int i;
int num_edges = NUM_EDGES (el);
basic_block bb;
FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
bb->aux = bb;
union_groups (EXIT_BLOCK_PTR, ENTRY_BLOCK_PTR);
for (i = 0; i < num_edges; i++)
{
edge e = INDEX_EDGE (el, i);
if (((e->flags & (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL | EDGE_FAKE))
|| e->dest == EXIT_BLOCK_PTR)
&& !EDGE_INFO (e)->ignore
&& (find_group (e->src) != find_group (e->dest)))
{
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);
}
}
for (i = 0; i < num_edges; i++)
{
edge e = INDEX_EDGE (el, i);
if (EDGE_CRITICAL_P (e) && !EDGE_INFO (e)->ignore
&& find_group (e->src) != find_group (e->dest))
{
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);
}
}
for (i = 0; i < num_edges; i++)
{
edge e = INDEX_EDGE (el, i);
if (!EDGE_INFO (e)->ignore
&& find_group (e->src) != find_group (e->dest))
{
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);
}
}
FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
bb->aux = NULL;
}
void
init_branch_prob (void)
{
int i;
total_num_blocks = 0;
total_num_edges = 0;
total_num_edges_ignored = 0;
total_num_edges_instrumented = 0;
total_num_blocks_created = 0;
total_num_passes = 0;
total_num_times_called = 0;
total_num_branches = 0;
total_num_never_executed = 0;
for (i = 0; i < 20; i++)
total_hist_br_prob[i] = 0;
}
void
end_branch_prob (void)
{
if (dump_file)
{
fprintf (dump_file, "\n");
fprintf (dump_file, "Total number of blocks: %d\n",
total_num_blocks);
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 (dump_file, "Total number of instrumented edges: %d\n",
total_num_edges_instrumented);
fprintf (dump_file, "Total number of blocks created: %d\n",
total_num_blocks_created);
fprintf (dump_file, "Total number of graph solution passes: %d\n",
total_num_passes);
if (total_num_times_called != 0)
fprintf (dump_file, "Average number of graph solution passes: %d\n",
(total_num_passes + (total_num_times_called >> 1))
/ total_num_times_called);
fprintf (dump_file, "Total number of branches: %d\n",
total_num_branches);
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 (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);
}
}
}
void
tree_register_profile_hooks (void)
{
profile_hooks = &tree_profile_hooks;
if (!ir_type ())
abort ();
}
void
rtl_register_profile_hooks (void)
{
profile_hooks = &rtl_profile_hooks;
if (ir_type ())
abort ();
}