X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fprofile.c;h=ac460464697cef6abbb60cb8bce2fac952a26c97;hb=73faef308beb68f43956ec108d6dc61a4ed1b3d6;hp=3f48be623d2d494bac5b600dd414facdf5d79797;hpb=ffedd2549f6fe6cd65d27e8608032b38c940e79d;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/profile.c b/gcc/profile.c index 3f48be623d2..ac460464697 100644 --- a/gcc/profile.c +++ b/gcc/profile.c @@ -1,6 +1,7 @@ /* 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, 2007, 2008, 2009 + 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. @@ -9,7 +10,7 @@ This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later +Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY @@ -18,9 +19,8 @@ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 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. */ +along with GCC; see the file COPYING3. If not see +. */ /* Generate basic block profile instrumentation and auxiliary files. Profile generation is optimized, so that not all arcs in the basic @@ -65,28 +65,15 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "tree.h" #include "cfghooks.h" #include "tree-flow.h" +#include "timevar.h" +#include "cfgloop.h" +#include "tree-pass.h" + +#include "profile.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; - - /* Is on the spanning tree. */ - unsigned int on_tree : 1; - - /* Pretend this edge does not exist (it is abnormal and we've - inserted a fake to compensate). */ - unsigned int ignore : 1; -}; - struct bb_info { unsigned int count_valid : 1; @@ -95,9 +82,9 @@ struct bb_info { gcov_type pred_count; }; -#define EDGE_INFO(e) ((struct edge_info *) (e)->aux) #define BB_INFO(b) ((struct bb_info *) (b)->aux) + /* Counter summary from the last set of coverage counts read. */ const struct gcov_ctr_summary *profile_info; @@ -113,7 +100,6 @@ 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; /* Forward declarations. */ @@ -126,7 +112,6 @@ static gcov_type * get_exec_counts (void); static basic_block find_group (basic_block); static void union_groups (basic_block, basic_block); - /* Add edge instrumentation code to the entire insn chain. F is the first insn of the chain. @@ -142,15 +127,15 @@ instrument_edges (struct edge_list *el) FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb) { edge e; + edge_iterator ei; - for (e = bb->succ; e; e = e->succ_next) + FOR_EACH_EDGE (e, ei, bb->succs) { struct edge_info *inf = EDGE_INFO (e); 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, @@ -195,8 +180,20 @@ instrument_values (histogram_values values) 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: - abort (); + gcc_unreachable (); } if (!coverage_counter_alloc (t, hist->n_counters)) continue; @@ -219,8 +216,20 @@ instrument_values (histogram_values values) (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: - abort (); + gcc_unreachable (); } } } @@ -239,7 +248,9 @@ get_exec_counts (void) FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb) { edge e; - for (e = bb->succ; e; e = e->succ_next) + edge_iterator ei; + + FOR_EACH_EDGE (e, ei, bb->succs) if (!EDGE_INFO (e)->ignore && !EDGE_INFO (e)->on_tree) num_edges++; } @@ -254,70 +265,144 @@ get_exec_counts (void) return counts; } - -/* Compute the branch probabilities for the various branches. - Annotate them accordingly. */ + +static bool +is_edge_inconsistent (VEC(edge,gc) *edges) +{ + edge e; + edge_iterator ei; + FOR_EACH_EDGE (e, ei, edges) + { + if (!EDGE_INFO (e)->ignore) + { + if (e->count < 0 + && (!(e->flags & EDGE_FAKE) + || !block_ends_with_call_p (e->src))) + { + if (dump_file) + { + fprintf (dump_file, + "Edge %i->%i is inconsistent, count"HOST_WIDEST_INT_PRINT_DEC, + e->src->index, e->dest->index, e->count); + dump_bb (e->src, dump_file, 0); + dump_bb (e->dest, dump_file, 0); + } + return true; + } + } + } + return false; +} static void -compute_branch_probabilities (void) +correct_negative_edge_counts (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; + edge e; + edge_iterator ei; - /* Very simple sanity checks so we catch bugs in our profiling code. */ - if (profile_info) + FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb) { - if (profile_info->run_max * profile_info->runs < profile_info->sum_max) - { - error ("corrupted profile info: run_max * runs < sum_max"); - exec_counts = NULL; - } + FOR_EACH_EDGE (e, ei, bb->succs) + { + if (e->count < 0) + e->count = 0; + } + } +} - if (profile_info->sum_all < profile_info->sum_max) +/* Check consistency. + Return true if inconsistency is found. */ +static bool +is_inconsistent (void) +{ + basic_block bb; + bool inconsistent = false; + FOR_EACH_BB (bb) + { + inconsistent |= is_edge_inconsistent (bb->preds); + if (!dump_file && inconsistent) + return true; + inconsistent |= is_edge_inconsistent (bb->succs); + if (!dump_file && inconsistent) + return true; + if (bb->count < 0) + { + if (dump_file) + { + fprintf (dump_file, "BB %i count is negative " + HOST_WIDEST_INT_PRINT_DEC, + bb->index, + bb->count); + dump_bb (bb, dump_file, 0); + } + inconsistent = true; + } + if (bb->count != sum_edge_counts (bb->preds)) + { + if (dump_file) + { + fprintf (dump_file, "BB %i count does not match sum of incoming edges " + HOST_WIDEST_INT_PRINT_DEC" should be " HOST_WIDEST_INT_PRINT_DEC, + bb->index, + bb->count, + sum_edge_counts (bb->preds)); + dump_bb (bb, dump_file, 0); + } + inconsistent = true; + } + if (bb->count != sum_edge_counts (bb->succs) && + ! (find_edge (bb, EXIT_BLOCK_PTR) != NULL && block_ends_with_call_p (bb))) { - error ("corrupted profile info: sum_all is smaller than sum_max"); - exec_counts = NULL; + if (dump_file) + { + fprintf (dump_file, "BB %i count does not match sum of outgoing edges " + HOST_WIDEST_INT_PRINT_DEC" should be " HOST_WIDEST_INT_PRINT_DEC, + bb->index, + bb->count, + sum_edge_counts (bb->succs)); + dump_bb (bb, dump_file, 0); + } + inconsistent = true; } + if (!dump_file && inconsistent) + return true; } - /* Attach extra info block to each bb. */ + return inconsistent; +} - alloc_aux_for_blocks (sizeof (struct bb_info)); +/* Set each basic block count to the sum of its outgoing edge counts */ +static void +set_bb_counts (void) +{ + basic_block bb; 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->count = sum_edge_counts (bb->succs); + gcc_assert (bb->count >= 0); } +} - /* Avoid predicting entry on exit nodes. */ - BB_INFO (EXIT_BLOCK_PTR)->succ_count = 2; - BB_INFO (ENTRY_BLOCK_PTR)->pred_count = 2; - +/* Reads profile data and returns total number of edge counts read */ +static int +read_profile_edge_counts (gcov_type *exec_counts) +{ + basic_block bb; + int num_edges = 0; + int exec_counts_pos = 0; /* For each edge not on the spanning tree, set its execution count from the .da file. */ - /* The first count in the .da file is the number of times that the function was entered. This is the exec_count for block zero. */ FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb) { edge e; - for (e = bb->succ; e; e = e->succ_next) + edge_iterator ei; + + FOR_EACH_EDGE (e, ei, bb->succs) if (!EDGE_INFO (e)->ignore && !EDGE_INFO (e)->on_tree) { num_edges++; @@ -346,6 +431,61 @@ compute_branch_probabilities (void) } } + return num_edges; +} + +/* Compute the branch probabilities for the various branches. + Annotate them accordingly. */ + +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_branches; + gcov_type *exec_counts = get_exec_counts (); + int inconsistent = 0; + + /* Very simple sanity checks so we catch bugs in our profiling code. */ + if (!profile_info) + return; + 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; + } + + /* Attach extra info block to each bb. */ + 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++; + } + + /* Avoid predicting entry on exit nodes. */ + BB_INFO (EXIT_BLOCK_PTR)->succ_count = 2; + BB_INFO (ENTRY_BLOCK_PTR)->pred_count = 2; + + num_edges = read_profile_edge_counts (exec_counts); + if (dump_file) fprintf (dump_file, "\n%d edge counts read\n", num_edges); @@ -380,9 +520,10 @@ compute_branch_probabilities (void) if (bi->succ_count == 0) { edge e; + edge_iterator ei; gcov_type total = 0; - for (e = bb->succ; e; e = e->succ_next) + FOR_EACH_EDGE (e, ei, bb->succs) total += e->count; bb->count = total; bi->count_valid = 1; @@ -391,9 +532,10 @@ compute_branch_probabilities (void) else if (bi->pred_count == 0) { edge e; + edge_iterator ei; gcov_type total = 0; - for (e = bb->pred; e; e = e->pred_next) + FOR_EACH_EDGE (e, ei, bb->preds) total += e->count; bb->count = total; bi->count_valid = 1; @@ -405,23 +547,23 @@ compute_branch_probabilities (void) if (bi->succ_count == 1) { edge e; + edge_iterator ei; gcov_type total = 0; /* One of the counts will be invalid, but it is zero, so adding it in also doesn't hurt. */ - for (e = bb->succ; e; e = e->succ_next) + FOR_EACH_EDGE (e, ei, bb->succs) total += e->count; - /* Seedgeh for the invalid edge, and set its count. */ - for (e = bb->succ; e; e = e->succ_next) + /* Search for the invalid edge, and set its count. */ + FOR_EACH_EDGE (e, ei, bb->succs) if (! EDGE_INFO (e)->count_valid && ! EDGE_INFO (e)->ignore) break; /* 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--; @@ -432,23 +574,23 @@ compute_branch_probabilities (void) if (bi->pred_count == 1) { edge e; + edge_iterator ei; gcov_type total = 0; /* One of the counts will be invalid, but it is zero, so adding it in also doesn't hurt. */ - for (e = bb->pred; e; e = e->pred_next) + FOR_EACH_EDGE (e, ei, bb->preds) total += e->count; /* Search for the invalid edge, and set its count. */ - for (e = bb->pred; e; e = e->pred_next) + FOR_EACH_EDGE (e, ei, bb->preds) if (!EDGE_INFO (e)->count_valid && !EDGE_INFO (e)->ignore) break; /* 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--; @@ -460,7 +602,7 @@ compute_branch_probabilities (void) } } if (dump_file) - dump_flow_info (dump_file); + dump_flow_info (dump_file, dump_flags); total_num_passes += passes; if (dump_file) @@ -470,22 +612,45 @@ compute_branch_probabilities (void) 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); } + /* Check for inconsistent basic block counts */ + inconsistent = is_inconsistent (); + + if (inconsistent) + { + if (flag_profile_correction) + { + /* Inconsistency detected. Make it flow-consistent. */ + static int informed = 0; + if (informed == 0) + { + informed = 1; + inform (input_location, "correcting inconsistent profile data"); + } + correct_negative_edge_counts (); + /* Set bb counts to the sum of the outgoing edge counts */ + set_bb_counts (); + if (dump_file) + fprintf (dump_file, "\nCalling mcf_smooth_cfg\n"); + mcf_smooth_cfg (); + } + else + error ("corrupted profile info: profile data is not flow-consistent"); + } + /* For every edge, calculate its branch probability and add a reg_note to the branch insn to indicate this. */ 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; + edge_iterator ei; if (bb->count < 0) { @@ -493,7 +658,7 @@ compute_branch_probabilities (void) bb->index, (int)bb->count); bb->count = 0; } - for (e = bb->succ; e; e = e->succ_next) + FOR_EACH_EDGE (e, ei, bb->succs) { /* Function may return twice in the cased the called function is setjmp or calls fork, but we can't represent this by extra @@ -518,11 +683,11 @@ compute_branch_probabilities (void) } if (bb->count) { - for (e = bb->succ; e; e = e->succ_next) + 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) - && bb->succ->succ_next) + && EDGE_COUNT (bb->succs) >= 2) { int prob; edge e; @@ -530,9 +695,9 @@ compute_branch_probabilities (void) /* Find the branch edge. It is possible that we do have fake edges here. */ - for (e = bb->succ; e->flags & (EDGE_FAKE | EDGE_FALLTHRU); - e = e->succ_next) - continue; /* Loop body has been intentionally left blank. */ + 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; @@ -541,37 +706,24 @@ compute_branch_probabilities (void) 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 distribute the probabilities evenly so we get sane - sum. Use simple heuristics that if there are normal edges, + /* 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 frequency over abnormals (this is the case of noreturn calls). */ - else + else if (profile_status == PROFILE_ABSENT) { int total = 0; - for (e = bb->succ; e; e = e->succ_next) + FOR_EACH_EDGE (e, ei, bb->succs) if (!(e->flags & (EDGE_COMPLEX | EDGE_FAKE))) total ++; if (total) { - for (e = bb->succ; e; e = e->succ_next) + FOR_EACH_EDGE (e, ei, bb->succs) if (!(e->flags & (EDGE_COMPLEX | EDGE_FAKE))) e->probability = REG_BR_PROB_BASE / total; else @@ -579,24 +731,22 @@ compute_branch_probabilities (void) } else { - for (e = bb->succ; e; e = e->succ_next) - total ++; - for (e = bb->succ; e; e = e->succ_next) + total += EDGE_COUNT (bb->succs); + 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) - && bb->succ->succ_next) - num_branches++, num_never_executed; + && EDGE_COUNT (bb->succs) >= 2) + num_branches++; } } counts_to_freqs (); + profile_status = PROFILE_READ; 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", @@ -604,7 +754,6 @@ compute_branch_probabilities (void) 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]; @@ -616,7 +765,7 @@ compute_branch_probabilities (void) } /* 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) @@ -626,14 +775,13 @@ 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; } @@ -658,26 +806,18 @@ compute_value_histograms (histogram_values values) for (i = 0; i < VEC_length (histogram_value, values); i++) { - rtx hist_list = NULL_RTX; + histogram_value hist = VEC_index (histogram_value, values, i); + gimple stmt = hist->hvalue.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; + + 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++) @@ -685,7 +825,9 @@ compute_value_histograms (histogram_values values) 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. */ @@ -777,6 +919,7 @@ branch_prob (void) int need_exit_edge = 0, need_entry_edge = 0; int have_exit_edge = 0, have_entry_edge = 0; edge e; + edge_iterator ei; /* Functions returning multiple times are not handled by extra edges. Instead we simply allow negative counts on edges from exit to the @@ -784,15 +927,47 @@ branch_prob (void) with the extra edges because that would result in flowgraph that needs to have fake edges outside the spanning tree. */ - for (e = bb->succ; e; e = e->succ_next) + FOR_EACH_EDGE (e, ei, bb->succs) { + gimple_stmt_iterator gsi; + gimple 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 (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi_prev (&gsi)) + { + last = gsi_stmt (gsi); + if (gimple_has_location (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 + && gimple_has_location (last) + && e->goto_locus != UNKNOWN_LOCATION + && !single_succ_p (bb) + && (LOCATION_FILE (e->goto_locus) + != LOCATION_FILE (gimple_location (last)) + || (LOCATION_LINE (e->goto_locus) + != LOCATION_LINE (gimple_location (last))))) + { + basic_block new_bb = split_edge (e); + edge ne = single_succ_edge (new_bb); + ne->goto_locus = e->goto_locus; + ne->goto_block = e->goto_block; + } 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) + FOR_EACH_EDGE (e, ei, bb->preds) { if ((e->flags & (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL)) && e->src != ENTRY_BLOCK_PTR) @@ -863,7 +1038,7 @@ branch_prob (void) 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); @@ -884,7 +1059,7 @@ branch_prob (void) 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); } @@ -892,7 +1067,7 @@ branch_prob (void) /* 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 */ @@ -903,11 +1078,12 @@ branch_prob (void) 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 (e = bb->succ; e; e = e->succ_next) + FOR_EACH_EDGE (e, ei, bb->succs) { struct edge_info *i = EDGE_INFO (e); if (!i->ignore) @@ -922,8 +1098,7 @@ branch_prob (void) 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; @@ -939,116 +1114,52 @@ branch_prob (void) /* 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; - - FOR_EACH_BB (bb) - { - rtx insn = BB_HEAD (bb); - int ignore_next_note = 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); + gimple_stmt_iterator gsi; - 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, NOTE_LINE_NUMBER (insn), &offset, bb); - } - } - insn = NEXT_INSN (insn); - } + offset = 0; - 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 (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) { - 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); - } + gimple stmt = gsi_stmt (gsi); + if (gimple_has_location (stmt)) + output_location (gimple_filename (stmt), gimple_lineno (stmt), + &offset, bb); + } - /* Notice GOTO expressions we eliminated while constructing the - CFG. */ - if (bb->succ && !bb->succ->succ_next && bb->succ->goto_locus) - { - /* ??? source_locus type is marked deprecated in input.h. */ - source_locus curr_location = bb->succ->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); -#else - output_location (curr_location->file, curr_location->line, - &offset, bb); -#endif - } + /* Notice GOTO expressions we eliminated while constructing the + CFG. */ + if (single_succ_p (bb) + && single_succ_edge (bb)->goto_locus != UNKNOWN_LOCATION) + { + location_t curr_location = single_succ_edge (bb)->goto_locus; + /* ??? The FILE/LINE API is inconsistent for these cases. */ + output_location (LOCATION_FILE (curr_location), + LOCATION_LINE (curr_location), &offset, bb); + } - 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; @@ -1071,38 +1182,26 @@ branch_prob (void) if (profile_arc_flag && coverage_counter_alloc (GCOV_COUNTER_ARCS, num_instrumented)) { - unsigned n_instrumented = instrument_edges (el); + unsigned n_instrumented; - if (n_instrumented != num_instrumented) - abort (); + profile_hooks->init_edge_profiler (); + + n_instrumented = instrument_edges (el); + + gcc_assert (n_instrumented == num_instrumented); if (flag_profile_values) instrument_values (values); /* Commit changes done by instrumentation. */ - if (ir_type ()) - bsi_commit_edge_inserts ((int *)NULL); - else - { - commit_edge_insertions_watch_calls (); - allocate_reg_info (max_reg_num (), FALSE, FALSE); - } + gsi_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 (); } /* Union find algorithm implementation for the basic blocks using @@ -1134,8 +1233,7 @@ union_groups (basic_block bb1, basic_block bb2) /* ??? 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; } @@ -1229,7 +1327,6 @@ init_branch_prob (void) 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; } @@ -1260,8 +1357,6 @@ end_branch_prob (void) / 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; @@ -1279,17 +1374,6 @@ end_branch_prob (void) void tree_register_profile_hooks (void) { + gcc_assert (current_ir_type () == IR_GIMPLE); profile_hooks = &tree_profile_hooks; - if (!ir_type ()) - abort (); -} - -/* Set up hooks to enable RTL-based profiling. */ - -void -rtl_register_profile_hooks (void) -{ - profile_hooks = &rtl_profile_hooks; - if (ir_type ()) - abort (); }