#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"
#include "timevar.h"
#include "cfgloop.h"
#include "tree-pass.h"
static struct profile_hooks* profile_hooks;
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 (histogram_values);
static void compute_branch_probabilities (void);
static void compute_value_histograms (histogram_values);
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;
FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
{
edge e;
edge_iterator ei;
FOR_EACH_EDGE (e, ei, bb->succs)
{
struct edge_info *inf = EDGE_INFO (e);
if (!inf->ignore && !inf->on_tree)
{
gcc_assert (!(e->flags & EDGE_ABNORMAL));
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 (histogram_values values)
{
unsigned i, t;
for (i = 0; i < VEC_length (histogram_value, values); i++)
{
histogram_value hist = VEC_index (histogram_value, values, i);
switch (hist->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:
gcc_unreachable ();
}
if (!coverage_counter_alloc (t, hist->n_counters))
continue;
switch (hist->type)
{
case HIST_TYPE_INTERVAL:
(profile_hooks->gen_interval_profiler) (hist, t, 0);
break;
case HIST_TYPE_POW2:
(profile_hooks->gen_pow2_profiler) (hist, t, 0);
break;
case HIST_TYPE_SINGLE_VALUE:
(profile_hooks->gen_one_value_profiler) (hist, t, 0);
break;
case HIST_TYPE_CONST_DELTA:
(profile_hooks->gen_const_delta_profiler) (hist, t, 0);
break;
default:
gcc_unreachable ();
}
}
}
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;
edge_iterator ei;
FOR_EACH_EDGE (e, ei, bb->succs)
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;
edge_iterator ei;
FOR_EACH_EDGE (e, ei, bb->succs)
if (!EDGE_INFO (e)->ignore)
BB_INFO (bb)->succ_count++;
FOR_EACH_EDGE (e, ei, bb->preds)
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;
edge_iterator ei;
FOR_EACH_EDGE (e, ei, bb->succs)
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;
edge_iterator ei;
gcov_type total = 0;
FOR_EACH_EDGE (e, ei, bb->succs)
total += e->count;
bb->count = total;
bi->count_valid = 1;
changes = 1;
}
else if (bi->pred_count == 0)
{
edge e;
edge_iterator ei;
gcov_type total = 0;
FOR_EACH_EDGE (e, ei, bb->preds)
total += e->count;
bb->count = total;
bi->count_valid = 1;
changes = 1;
}
}
if (bi->count_valid)
{
if (bi->succ_count == 1)
{
edge e;
edge_iterator ei;
gcov_type total = 0;
FOR_EACH_EDGE (e, ei, bb->succs)
total += e->count;
FOR_EACH_EDGE (e, ei, bb->succs)
if (! EDGE_INFO (e)->count_valid && ! EDGE_INFO (e)->ignore)
break;
total = bb->count - total;
gcc_assert (e);
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;
edge_iterator ei;
gcov_type total = 0;
FOR_EACH_EDGE (e, ei, bb->preds)
total += e->count;
FOR_EACH_EDGE (e, ei, bb->preds)
if (!EDGE_INFO (e)->count_valid && !EDGE_INFO (e)->ignore)
break;
total = bb->count - total + e->count;
gcc_assert (e);
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, dump_flags);
total_num_passes += passes;
if (dump_file)
fprintf (dump_file, "Graph solving took %d passes.\n\n", passes);
FOR_EACH_BB (bb)
{
gcc_assert (!BB_INFO (bb)->succ_count && !BB_INFO (bb)->pred_count);
}
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;
edge_iterator ei;
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_EACH_EDGE (e, ei, bb->succs)
{
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_EACH_EDGE (e, ei, bb->succs)
e->probability = (e->count * REG_BR_PROB_BASE + bb->count / 2) / bb->count;
if (bb->index >= NUM_FIXED_BLOCKS
&& block_ends_with_condjump_p (bb)
&& EDGE_COUNT (bb->succs) >= 2)
{
int prob;
edge e;
int index;
FOR_EACH_EDGE (e, ei, bb->succs)
if (!(e->flags & (EDGE_FAKE | EDGE_FALLTHRU)))
break;
prob = e->probability;
index = prob * 20 / REG_BR_PROB_BASE;
if (index == 20)
index = 19;
hist_br_prob[index]++;
num_branches++;
}
}
else if (profile_status == PROFILE_ABSENT)
{
int total = 0;
FOR_EACH_EDGE (e, ei, bb->succs)
if (!(e->flags & (EDGE_COMPLEX | EDGE_FAKE)))
total ++;
if (total)
{
FOR_EACH_EDGE (e, ei, bb->succs)
if (!(e->flags & (EDGE_COMPLEX | EDGE_FAKE)))
e->probability = REG_BR_PROB_BASE / total;
else
e->probability = 0;
}
else
{
total += EDGE_COUNT (bb->succs);
FOR_EACH_EDGE (e, ei, bb->succs)
e->probability = REG_BR_PROB_BASE / total;
}
if (bb->index >= NUM_FIXED_BLOCKS
&& block_ends_with_condjump_p (bb)
&& EDGE_COUNT (bb->succs) >= 2)
num_branches++, num_never_executed;
}
}
counts_to_freqs ();
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 (histogram_values 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 < VEC_length (histogram_value, values); i++)
{
histogram_value hist = VEC_index (histogram_value, values, i);
n_histogram_counters[(int) hist->type] += hist->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 < VEC_length (histogram_value, values); i++)
{
histogram_value hist = VEC_index (histogram_value, values, i);
tree stmt = hist->hvalue.stmt;
stmt_ann_t ann = get_stmt_ann (stmt);
t = (int) hist->type;
aact_count = act_count[t];
act_count[t] += hist->n_counters;
hist->hvalue.next = ann->histograms;
ann->histograms = hist;
hist->hvalue.counters = XNEWVEC (gcov_type, hist->n_counters);
for (j = 0; j < hist->n_counters; j++)
hist->hvalue.counters[j] = aact_count[j];
}
for (t = 0; t < GCOV_N_VALUE_COUNTERS; t++)
if (histogram_counts[t])
free (histogram_counts[t]);
}
#define BB_TO_GCOV_INDEX(bb) ((bb)->index - 1)
static void
output_location (char const *file_name, int line,
gcov_position_t *offset, basic_block bb)
{
static char const *prev_file_name;
static int prev_line;
bool name_differs, line_differs;
if (!file_name)
{
prev_file_name = NULL;
prev_line = -1;
return;
}
name_differs = !prev_file_name || strcmp (file_name, prev_file_name);
line_differs = prev_line != line;
if (name_differs || line_differs)
{
if (!*offset)
{
*offset = gcov_write_tag (GCOV_TAG_LINES);
gcov_write_unsigned (BB_TO_GCOV_INDEX (bb));
name_differs = line_differs=true;
}
if (name_differs)
{
prev_file_name = file_name;
gcov_write_unsigned (0);
gcov_write_string (prev_file_name);
}
if (line_differs)
{
gcov_write_unsigned (line);
prev_line = line;
}
}
}
void
branch_prob (void)
{
basic_block bb;
unsigned i;
unsigned num_edges, ignored_edges;
unsigned num_instrumented;
struct edge_list *el;
histogram_values 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;
edge_iterator ei;
FOR_EACH_EDGE (e, ei, bb->succs)
{
block_stmt_iterator bsi;
tree last = NULL;
for (bsi = bsi_last (bb); !bsi_end_p (bsi); bsi_prev (&bsi))
{
last = bsi_stmt (bsi);
if (EXPR_LOCUS (last))
break;
}
if (last && EXPR_LOCUS (last)
&& e->goto_locus
&& !single_succ_p (bb)
#ifdef USE_MAPPED_LOCATION
&& (LOCATION_FILE (e->goto_locus)
!= LOCATION_FILE (EXPR_LOCATION (last))
|| (LOCATION_LINE (e->goto_locus)
!= LOCATION_LINE (EXPR_LOCATION (last)))))
#else
&& (e->goto_locus->file != EXPR_LOCUS (last)->file
|| (e->goto_locus->line != EXPR_LOCUS (last)->line)))
#endif
{
basic_block new = split_edge (e);
single_succ_edge (new)->goto_locus = e->goto_locus;
}
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_EACH_EDGE (e, ei, bb->preds)
{
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++;
}
}
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;
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); i++)
gcov_write_unsigned (0);
gcov_write_length (offset);
}
ENTRY_BLOCK_PTR->index = 1;
EXIT_BLOCK_PTR->index = last_basic_block;
if (coverage_begin_output ())
{
gcov_position_t offset;
FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb)
{
edge e;
edge_iterator ei;
offset = gcov_write_tag (GCOV_TAG_ARCS);
gcov_write_unsigned (BB_TO_GCOV_INDEX (bb));
FOR_EACH_EDGE (e, ei, bb->succs)
{
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;
if (e->flags & (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE)
&& e->src->next_bb == e->dest)
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 ())
{
gcov_position_t offset;
output_location (NULL, 0, NULL, NULL);
FOR_EACH_BB (bb)
{
block_stmt_iterator bsi;
offset = 0;
if (bb == ENTRY_BLOCK_PTR->next_bb)
{
expanded_location curr_location =
expand_location (DECL_SOURCE_LOCATION (current_function_decl));
output_location (curr_location.file, curr_location.line,
&offset, bb);
}
for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
{
tree stmt = bsi_stmt (bsi);
if (EXPR_HAS_LOCATION (stmt))
output_location (EXPR_FILENAME (stmt), EXPR_LINENO (stmt),
&offset, bb);
}
if (single_succ_p (bb) && single_succ_edge (bb)->goto_locus)
{
source_locus curr_location = single_succ_edge (bb)->goto_locus;
#ifdef USE_MAPPED_LOCATION
output_location (LOCATION_FILE (curr_location),
LOCATION_LINE (curr_location), &offset, bb);
#else
output_location (curr_location->file, curr_location->line,
&offset, bb);
#endif
}
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 (&values);
if (flag_branch_probabilities)
{
compute_branch_probabilities ();
if (flag_profile_values)
compute_value_histograms (values);
}
remove_fake_edges ();
if (profile_arc_flag
&& coverage_counter_alloc (GCOV_COUNTER_ARCS, num_instrumented))
{
unsigned n_instrumented;
profile_hooks->init_edge_profiler ();
n_instrumented = instrument_edges (el);
gcc_assert (n_instrumented == num_instrumented);
if (flag_profile_values)
instrument_values (values);
bsi_commit_edge_inserts ();
}
free_aux_for_edges ();
VEC_free (histogram_value, heap, values);
free_edge_list (el);
if (flag_branch_probabilities)
profile_status = PROFILE_READ;
coverage_end_function ();
}
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);
gcc_assert (bb1g != bb2g);
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)
{
gcc_assert (ir_type ());
profile_hooks = &tree_profile_hooks;
}