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;
-/* 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 {
unsigned int count_valid : 1;
t = GCOV_COUNTER_V_DELTA;
break;
+ case HIST_TYPE_INDIR_CALL:
+ t = GCOV_COUNTER_V_INDIR;
+ break;
+
+ case HIST_TYPE_AVERAGE:
+ t = GCOV_COUNTER_AVERAGE;
+ break;
+
+ case HIST_TYPE_IOR:
+ t = GCOV_COUNTER_IOR;
+ break;
+
default:
gcc_unreachable ();
}
(profile_hooks->gen_const_delta_profiler) (hist, t, 0);
break;
+ case HIST_TYPE_INDIR_CALL:
+ (profile_hooks->gen_ic_profiler) (hist, t, 0);
+ break;
+
+ case HIST_TYPE_AVERAGE:
+ (profile_hooks->gen_average_profiler) (hist, t, 0);
+ break;
+
+ case HIST_TYPE_IOR:
+ (profile_hooks->gen_ior_profiler) (hist, t, 0);
+ break;
+
default:
gcc_unreachable ();
}
}
- VEC_free (histogram_value, heap, values);
}
\f
}
}
if (dump_file)
- dump_flow_info (dump_file);
+ dump_flow_info (dump_file, dump_flags);
total_num_passes += passes;
if (dump_file)
{
edge e;
edge_iterator ei;
- rtx note;
if (bb->count < 0)
{
{
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)
{
index = 19;
hist_br_prob[index]++;
- /* 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++;
}
}
- /* Otherwise try to preserve the existing REG_BR_PROB probabilities
- 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));
-
- BRANCH_EDGE (bb)->probability = prob;
- FALLTHRU_EDGE (bb)->probability = REG_BR_PROB_BASE - prob;
- }
/* As a last resort, distribute the probabilities evenly.
Use simple heuristics that if there are normal edges,
give all abnormals frequency of 0, otherwise distribute the
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;
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;
- hist = VEC_index (histogram_value, values, i);
t = (int) hist->type;
aact_count = act_count[t];
act_count[t] += hist->n_counters;
- if (!ir_type ())
- {
- 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 (hist->hvalue.rtl.value), hist_list);
- hist_list = alloc_EXPR_LIST (0, GEN_INT (hist->type), hist_list);
- REG_NOTES (hist->hvalue.rtl.insn) =
- alloc_EXPR_LIST (REG_VALUE_PROFILE, hist_list,
- REG_NOTES (hist->hvalue.rtl.insn));
- }
- else
- {
- tree stmt = hist->hvalue.tree.stmt;
- stmt_ann_t ann = get_stmt_ann (stmt);
- hist->hvalue.tree.next = ann->histograms;
- ann->histograms = hist;
- hist->hvalue.tree.counters =
- xmalloc (sizeof (gcov_type) * hist->n_counters);
- for (j = 0; j < hist->n_counters; j++)
- hist->hvalue.tree.counters[j] = aact_count[j];
- }
+ gimple_add_histogram_value (cfun, stmt, 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++)
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 */
flag_bits |= GCOV_ARC_FALLTHROUGH;
/* On trees we don't have fallthru flags, but we can
recompute them from CFG shape. */
- if (ir_type ()
- && e->flags & (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE)
+ if (e->flags & (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE)
&& e->src->next_bb == e->dest)
flag_bits |= GCOV_ARC_FALLTHROUGH;
/* Line numbers. */
if (coverage_begin_output ())
{
+ gcov_position_t offset;
+
/* Initialize the output. */
output_location (NULL, 0, NULL, NULL);
- if (!ir_type ())
+ FOR_EACH_BB (bb)
{
- gcov_position_t offset;
+ block_stmt_iterator bsi;
- FOR_EACH_BB (bb)
- {
- rtx insn = BB_HEAD (bb);
- int ignore_next_note = 0;
-
- offset = 0;
+ offset = 0;
- /* We are looking for line number notes. Search backward
- before basic block to find correct ones. */
- insn = prev_nonnote_insn (insn);
- if (!insn)
- insn = get_insns ();
- else
- insn = NEXT_INSN (insn);
-
- while (insn != BB_END (bb))
- {
- if (NOTE_P (insn))
- {
- /* Must ignore the line number notes that
- immediately follow the end of an inline function
- to avoid counting it twice. There is a note
- before the call, and one after the call. */
- if (NOTE_LINE_NUMBER (insn)
- == NOTE_INSN_REPEATED_LINE_NUMBER)
- ignore_next_note = 1;
- else if (NOTE_LINE_NUMBER (insn) <= 0)
- /*NOP*/;
- else if (ignore_next_note)
- ignore_next_note = 0;
- else
- {
- expanded_location s;
- NOTE_EXPANDED_LOCATION (s, insn);
- output_location (s.file, s.line, &offset, bb);
- }
- }
- insn = NEXT_INSN (insn);
- }
-
- if (offset)
- {
- /* A file of NULL indicates the end of run. */
- gcov_write_unsigned (0);
- gcov_write_string (NULL);
- gcov_write_length (offset);
- }
+ 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);
}
- }
- else
- {
- gcov_position_t offset;
- FOR_EACH_BB (bb)
+ for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
{
- 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);
- }
+ tree stmt = bsi_stmt (bsi);
+ if (EXPR_HAS_LOCATION (stmt))
+ output_location (EXPR_FILENAME (stmt), EXPR_LINENO (stmt),
+ &offset, bb);
+ }
- /* Notice GOTO expressions we eliminated while constructing the
- CFG. */
- if (single_succ_p (bb) && single_succ_edge (bb)->goto_locus)
- {
- /* ??? source_locus type is marked deprecated in input.h. */
- source_locus curr_location = single_succ_edge (bb)->goto_locus;
- /* ??? The FILE/LINE API is inconsistent for these cases. */
+ /* Notice GOTO expressions we eliminated while constructing the
+ CFG. */
+ if (single_succ_p (bb) && single_succ_edge (bb)->goto_locus)
+ {
+ /* ??? source_locus type is marked deprecated in input.h. */
+ 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),
- LOCATION_LINE (curr_location),
- &offset, bb);
+ output_location (LOCATION_FILE (curr_location),
+ LOCATION_LINE (curr_location), &offset, bb);
#else
- output_location (curr_location->file, curr_location->line,
- &offset, bb);
+ output_location (curr_location->file, curr_location->line,
+ &offset, bb);
#endif
- }
+ }
- if (offset)
- {
- /* A file of NULL indicates the end of run. */
- gcov_write_unsigned (0);
- gcov_write_string (NULL);
- gcov_write_length (offset);
- }
+ if (offset)
+ {
+ /* A file of NULL indicates the end of run. */
+ gcov_write_unsigned (0);
+ gcov_write_string (NULL);
+ gcov_write_length (offset);
}
- }
+ }
}
ENTRY_BLOCK_PTR->index = ENTRY_BLOCK;
instrument_values (values);
/* Commit changes done by instrumentation. */
- if (ir_type ())
- bsi_commit_edge_inserts ();
- else
- {
- commit_edge_insertions_watch_calls ();
- allocate_reg_info (max_reg_num (), FALSE, FALSE);
- }
+ bsi_commit_edge_inserts ();
}
free_aux_for_edges ();
- 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());
- }
-
+ VEC_free (histogram_value, heap, 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
void
tree_register_profile_hooks (void)
{
- gcc_assert (ir_type ());
+ gcc_assert (current_ir_type () == IR_GIMPLE);
profile_hooks = &tree_profile_hooks;
}
-/* Set up hooks to enable RTL-based profiling. */
-
-void
-rtl_register_profile_hooks (void)
-{
- gcc_assert (!ir_type ());
- profile_hooks = &rtl_profile_hooks;
-}