/* Calculate branch probabilities, and basic block execution counts.
Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, 1999,
- 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ 2000, 2001, 2002, 2003, 2004, 2005 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.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
/* Generate basic block profile instrumentation and auxiliary files.
Profile generation is optimized, so that not all arcs in the basic
#include "tree.h"
#include "cfghooks.h"
#include "tree-flow.h"
+#include "timevar.h"
+#include "cfgloop.h"
+#include "tree-pass.h"
/* Hooks for profiling. */
static struct profile_hooks* profile_hooks;
if (!inf->ignore && !inf->on_tree)
{
- if (e->flags & EDGE_ABNORMAL)
- abort ();
+ 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,
break;
default:
- abort ();
+ gcc_unreachable ();
}
if (!coverage_counter_alloc (t, hist->n_counters))
continue;
break;
default:
- abort ();
+ gcc_unreachable ();
}
}
+ VEC_free (histogram_value, heap, values);
}
\f
/* Calculate count for remaining edge by conservation. */
total = bb->count - total;
- if (! e)
- abort ();
+ gcc_assert (e);
EDGE_INFO (e)->count_valid = 1;
e->count = total;
bi->succ_count--;
/* Calculate count for remaining edge by conservation. */
total = bb->count - total + e->count;
- if (! e)
- abort ();
+ gcc_assert (e);
EDGE_INFO (e)->count_valid = 1;
e->count = total;
bi->pred_count--;
succ and pred count of zero. */
FOR_EACH_BB (bb)
{
- if (BB_INFO (bb)->succ_count || BB_INFO (bb)->pred_count)
- abort ();
+ gcc_assert (!BB_INFO (bb)->succ_count && !BB_INFO (bb)->pred_count);
}
/* For every edge, calculate its branch probability and add a reg_note
{
FOR_EACH_EDGE (e, ei, bb->succs)
e->probability = (e->count * REG_BR_PROB_BASE + bb->count / 2) / bb->count;
- if (bb->index >= 0
+ if (bb->index >= NUM_FIXED_BLOCKS
&& block_ends_with_condjump_p (bb)
&& EDGE_COUNT (bb->succs) >= 2)
{
}
}
/* Otherwise try to preserve the existing REG_BR_PROB probabilities
- tree based profile guessing put into code. */
+ tree based profile guessing put into code. BB can be the
+ ENTRY_BLOCK, and it can have multiple (fake) successors in
+ EH cases, but it still has no code; don't crash in this case. */
else if (profile_status == PROFILE_ABSENT
&& !ir_type ()
&& EDGE_COUNT (bb->succs) > 1
+ && BB_END (bb)
&& (note = find_reg_note (BB_END (bb), REG_BR_PROB, 0)))
{
int prob = INTVAL (XEXP (note, 0));
FOR_EACH_EDGE (e, ei, bb->succs)
e->probability = REG_BR_PROB_BASE / total;
}
- if (bb->index >= 0
+ if (bb->index >= NUM_FIXED_BLOCKS
&& block_ends_with_condjump_p (bb)
&& EDGE_COUNT (bb->succs) >= 2)
num_branches++, num_never_executed;
}
/* Load value histograms values whose description is stored in VALUES array
- from .da file. */
+ from .gcda file. */
static void
compute_value_histograms (histogram_values values)
gcov_type *histogram_counts[GCOV_N_VALUE_COUNTERS];
gcov_type *act_count[GCOV_N_VALUE_COUNTERS];
gcov_type *aact_count;
- histogram_value hist;
for (t = 0; t < GCOV_N_VALUE_COUNTERS; t++)
n_histogram_counters[t] = 0;
for (i = 0; i < VEC_length (histogram_value, values); i++)
{
- hist = VEC_index (histogram_value, values, i);
+ histogram_value hist = VEC_index (histogram_value, values, i);
n_histogram_counters[(int) hist->type] += hist->n_counters;
}
for (i = 0; i < VEC_length (histogram_value, values); i++)
{
- rtx hist_list = NULL_RTX;
+ histogram_value hist = VEC_index (histogram_value, values, i);
+ tree stmt = hist->hvalue.stmt;
+ stmt_ann_t ann = get_stmt_ann (stmt);
- hist = VEC_index (histogram_value, values, i);
t = (int) hist->type;
- /* FIXME: make this work for trees. */
- if (!ir_type ())
- {
- aact_count = act_count[t];
- act_count[t] += hist->n_counters;
- for (j = hist->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) hist->value), hist_list);
- hist_list = alloc_EXPR_LIST (0, GEN_INT (hist->type), hist_list);
- REG_NOTES ((rtx) hist->insn) =
- alloc_EXPR_LIST (REG_VALUE_PROFILE, hist_list,
- REG_NOTES ((rtx) hist->insn));
- }
+ aact_count = act_count[t];
+ act_count[t] += hist->n_counters;
+
+ hist->hvalue.next = ann->histograms;
+ ann->histograms = hist;
+ hist->hvalue.counters =
+ xmalloc (sizeof (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++)
free (histogram_counts[t]);
}
-#define BB_TO_GCOV_INDEX(bb) ((bb)->index + 1)
+/* The entry basic block will be moved around so that it has index=1,
+ there is nothing at index 0 and the exit is at n_basic_block. */
+#define BB_TO_GCOV_INDEX(bb) ((bb)->index - 1)
/* When passed NULL as file_name, initialize.
When passed something else, output the necessary commands to change
line to LINE and offset to FILE_NAME. */
FOR_EACH_EDGE (e, ei, bb->succs)
{
+ block_stmt_iterator bsi;
+ tree last = NULL;
+
+ /* It may happen that there are compiler generated statements
+ without a locus at all. Go through the basic block from the
+ last to the first statement looking for a locus. */
+ for (bsi = bsi_last (bb); !bsi_end_p (bsi); bsi_prev (&bsi))
+ {
+ last = bsi_stmt (bsi);
+ if (EXPR_LOCUS (last))
+ break;
+ }
+
+ /* Edge with goto locus might get wrong coverage info unless
+ it is the only edge out of BB.
+ Don't do that when the locuses match, so
+ if (blah) goto something;
+ is not computed twice. */
+ 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;
num_instrumented++;
}
- total_num_blocks += n_basic_blocks + 2;
+ total_num_blocks += n_basic_blocks;
if (dump_file)
fprintf (dump_file, "%d basic blocks\n", n_basic_blocks);
gcov_position_t offset;
offset = gcov_write_tag (GCOV_TAG_BLOCKS);
- for (i = 0; i != (unsigned) (n_basic_blocks + 2); i++)
+ for (i = 0; i != (unsigned) (n_basic_blocks); i++)
gcov_write_unsigned (0);
gcov_write_length (offset);
}
/* Keep all basic block indexes nonnegative in the gcov output.
Index 0 is used for entry block, last index is for exit block.
*/
- ENTRY_BLOCK_PTR->index = -1;
+ ENTRY_BLOCK_PTR->index = 1;
EXIT_BLOCK_PTR->index = last_basic_block;
/* Arcs */
/* Notice GOTO expressions we eliminated while constructing the
CFG. */
- if (EDGE_COUNT (bb->succs) == 1 && EDGE_SUCC (bb, 0)->goto_locus)
+ if (single_succ_p (bb) && single_succ_edge (bb)->goto_locus)
{
/* ??? source_locus type is marked deprecated in input.h. */
- source_locus curr_location = EDGE_SUCC (bb, 0)->goto_locus;
+ source_locus curr_location = single_succ_edge (bb)->goto_locus;
/* ??? The FILE/LINE API is inconsistent for these cases. */
#ifdef USE_MAPPED_LOCATION
output_location (LOCATION_FILE (curr_location),
n_instrumented = instrument_edges (el);
- if (n_instrumented != num_instrumented)
- abort ();
+ gcc_assert (n_instrumented == num_instrumented);
if (flag_profile_values)
instrument_values (values);
free_edge_list (el);
if (flag_branch_probabilities)
profile_status = PROFILE_READ;
+ coverage_end_function ();
}
\f
/* Union find algorithm implementation for the basic blocks using
/* ??? I don't have a place for the rank field. OK. Lets go w/o it,
this code is unlikely going to be performance problem anyway. */
- if (bb1g == bb2g)
- abort ();
+ gcc_assert (bb1g != bb2g);
bb1g->aux = bb2g;
}
void
tree_register_profile_hooks (void)
{
+ gcc_assert (ir_type ());
profile_hooks = &tree_profile_hooks;
- if (!ir_type ())
- abort ();
}
-/* Set up hooks to enable RTL-based profiling. */
-
-void
-rtl_register_profile_hooks (void)
+\f
+/* Do branch profiling and static profile estimation passes. */
+static void
+rest_of_handle_branch_prob (void)
{
- profile_hooks = &rtl_profile_hooks;
- if (ir_type ())
- abort ();
+ struct loops loops;
+
+ /* Discover and record the loop depth at the head of each basic
+ block. The loop infrastructure does the real job for us. */
+ flow_loops_find (&loops);
+
+ if (dump_file)
+ flow_loops_dump (&loops, dump_file, NULL, 0);
+
+ /* Estimate using heuristics if no profiling info is available. */
+ if (flag_guess_branch_prob
+ && profile_status == PROFILE_ABSENT)
+ estimate_probability (&loops);
+
+ flow_loops_free (&loops);
+ free_dominance_info (CDI_DOMINATORS);
}
+
+struct tree_opt_pass pass_branch_prob =
+{
+ "bp", /* name */
+ NULL, /* gate */
+ rest_of_handle_branch_prob, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_BRANCH_PROB, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_dump_func, /* todo_flags_finish */
+ 'b' /* letter */
+};
+
+
+