00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052 #include "config.h"
00053 #include "system.h"
00054 #include "coretypes.h"
00055 #include "tm.h"
00056 #include "rtl.h"
00057 #include "flags.h"
00058 #include "output.h"
00059 #include "regs.h"
00060 #include "expr.h"
00061 #include "function.h"
00062 #include "toplev.h"
00063 #include "coverage.h"
00064 #include "value-prof.h"
00065 #include "tree.h"
00066 #include "cfghooks.h"
00067 #include "tree-flow.h"
00068 #include "timevar.h"
00069 #include "cfgloop.h"
00070 #include "tree-pass.h"
00071
00072
00073 static struct profile_hooks* profile_hooks;
00074
00075
00076 struct edge_info {
00077 unsigned int count_valid : 1;
00078
00079
00080 unsigned int on_tree : 1;
00081
00082
00083
00084 unsigned int ignore : 1;
00085 };
00086
00087 struct bb_info {
00088 unsigned int count_valid : 1;
00089
00090
00091 gcov_type succ_count;
00092 gcov_type pred_count;
00093 };
00094
00095 #define EDGE_INFO(e) ((struct edge_info *) (e)->aux)
00096 #define BB_INFO(b) ((struct bb_info *) (b)->aux)
00097
00098
00099
00100 const struct gcov_ctr_summary *profile_info;
00101
00102
00103
00104
00105 static int total_num_blocks;
00106 static int total_num_edges;
00107 static int total_num_edges_ignored;
00108 static int total_num_edges_instrumented;
00109 static int total_num_blocks_created;
00110 static int total_num_passes;
00111 static int total_num_times_called;
00112 static int total_hist_br_prob[20];
00113 static int total_num_never_executed;
00114 static int total_num_branches;
00115
00116
00117 static void find_spanning_tree (struct edge_list *);
00118 static unsigned instrument_edges (struct edge_list *);
00119 static void instrument_values (histogram_values);
00120 static void compute_branch_probabilities (void);
00121 static void compute_value_histograms (histogram_values);
00122 static gcov_type * get_exec_counts (void);
00123 static basic_block find_group (basic_block);
00124 static void union_groups (basic_block, basic_block);
00125
00126
00127
00128
00129
00130
00131
00132 static unsigned
00133 instrument_edges (struct edge_list *el)
00134 {
00135 unsigned num_instr_edges = 0;
00136 int num_edges = NUM_EDGES (el);
00137 basic_block bb;
00138
00139 FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
00140 {
00141 edge e;
00142 edge_iterator ei;
00143
00144 FOR_EACH_EDGE (e, ei, bb->succs)
00145 {
00146 struct edge_info *inf = EDGE_INFO (e);
00147
00148 if (!inf->ignore && !inf->on_tree)
00149 {
00150 gcc_assert (!(e->flags & EDGE_ABNORMAL));
00151 if (dump_file)
00152 fprintf (dump_file, "Edge %d to %d instrumented%s\n",
00153 e->src->index, e->dest->index,
00154 EDGE_CRITICAL_P (e) ? " (and split)" : "");
00155 (profile_hooks->gen_edge_profiler) (num_instr_edges++, e);
00156 }
00157 }
00158 }
00159
00160 total_num_blocks_created += num_edges;
00161 if (dump_file)
00162 fprintf (dump_file, "%d edges instrumented\n", num_instr_edges);
00163 return num_instr_edges;
00164 }
00165
00166
00167 static void
00168 instrument_values (histogram_values values)
00169 {
00170 unsigned i, t;
00171
00172
00173
00174 for (i = 0; i < VEC_length (histogram_value, values); i++)
00175 {
00176 histogram_value hist = VEC_index (histogram_value, values, i);
00177 switch (hist->type)
00178 {
00179 case HIST_TYPE_INTERVAL:
00180 t = GCOV_COUNTER_V_INTERVAL;
00181 break;
00182
00183 case HIST_TYPE_POW2:
00184 t = GCOV_COUNTER_V_POW2;
00185 break;
00186
00187 case HIST_TYPE_SINGLE_VALUE:
00188 t = GCOV_COUNTER_V_SINGLE;
00189 break;
00190
00191 case HIST_TYPE_CONST_DELTA:
00192 t = GCOV_COUNTER_V_DELTA;
00193 break;
00194
00195 default:
00196 gcc_unreachable ();
00197 }
00198 if (!coverage_counter_alloc (t, hist->n_counters))
00199 continue;
00200
00201 switch (hist->type)
00202 {
00203 case HIST_TYPE_INTERVAL:
00204 (profile_hooks->gen_interval_profiler) (hist, t, 0);
00205 break;
00206
00207 case HIST_TYPE_POW2:
00208 (profile_hooks->gen_pow2_profiler) (hist, t, 0);
00209 break;
00210
00211 case HIST_TYPE_SINGLE_VALUE:
00212 (profile_hooks->gen_one_value_profiler) (hist, t, 0);
00213 break;
00214
00215 case HIST_TYPE_CONST_DELTA:
00216 (profile_hooks->gen_const_delta_profiler) (hist, t, 0);
00217 break;
00218
00219 default:
00220 gcc_unreachable ();
00221 }
00222 }
00223 }
00224
00225
00226
00227
00228 static gcov_type *
00229 get_exec_counts (void)
00230 {
00231 unsigned num_edges = 0;
00232 basic_block bb;
00233 gcov_type *counts;
00234
00235
00236 FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
00237 {
00238 edge e;
00239 edge_iterator ei;
00240
00241 FOR_EACH_EDGE (e, ei, bb->succs)
00242 if (!EDGE_INFO (e)->ignore && !EDGE_INFO (e)->on_tree)
00243 num_edges++;
00244 }
00245
00246 counts = get_coverage_counts (GCOV_COUNTER_ARCS, num_edges, &profile_info);
00247 if (!counts)
00248 return NULL;
00249
00250 if (dump_file && profile_info)
00251 fprintf(dump_file, "Merged %u profiles with maximal count %u.\n",
00252 profile_info->runs, (unsigned) profile_info->sum_max);
00253
00254 return counts;
00255 }
00256
00257
00258
00259
00260
00261 static void
00262 compute_branch_probabilities (void)
00263 {
00264 basic_block bb;
00265 int i;
00266 int num_edges = 0;
00267 int changes;
00268 int passes;
00269 int hist_br_prob[20];
00270 int num_never_executed;
00271 int num_branches;
00272 gcov_type *exec_counts = get_exec_counts ();
00273 int exec_counts_pos = 0;
00274
00275
00276 if (profile_info)
00277 {
00278 if (profile_info->run_max * profile_info->runs < profile_info->sum_max)
00279 {
00280 error ("corrupted profile info: run_max * runs < sum_max");
00281 exec_counts = NULL;
00282 }
00283
00284 if (profile_info->sum_all < profile_info->sum_max)
00285 {
00286 error ("corrupted profile info: sum_all is smaller than sum_max");
00287 exec_counts = NULL;
00288 }
00289 }
00290
00291
00292
00293 alloc_aux_for_blocks (sizeof (struct bb_info));
00294 FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
00295 {
00296 edge e;
00297 edge_iterator ei;
00298
00299 FOR_EACH_EDGE (e, ei, bb->succs)
00300 if (!EDGE_INFO (e)->ignore)
00301 BB_INFO (bb)->succ_count++;
00302 FOR_EACH_EDGE (e, ei, bb->preds)
00303 if (!EDGE_INFO (e)->ignore)
00304 BB_INFO (bb)->pred_count++;
00305 }
00306
00307
00308 BB_INFO (EXIT_BLOCK_PTR)->succ_count = 2;
00309 BB_INFO (ENTRY_BLOCK_PTR)->pred_count = 2;
00310
00311
00312
00313
00314
00315
00316
00317 FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
00318 {
00319 edge e;
00320 edge_iterator ei;
00321
00322 FOR_EACH_EDGE (e, ei, bb->succs)
00323 if (!EDGE_INFO (e)->ignore && !EDGE_INFO (e)->on_tree)
00324 {
00325 num_edges++;
00326 if (exec_counts)
00327 {
00328 e->count = exec_counts[exec_counts_pos++];
00329 if (e->count > profile_info->sum_max)
00330 {
00331 error ("corrupted profile info: edge from %i to %i exceeds maximal count",
00332 bb->index, e->dest->index);
00333 }
00334 }
00335 else
00336 e->count = 0;
00337
00338 EDGE_INFO (e)->count_valid = 1;
00339 BB_INFO (bb)->succ_count--;
00340 BB_INFO (e->dest)->pred_count--;
00341 if (dump_file)
00342 {
00343 fprintf (dump_file, "\nRead edge from %i to %i, count:",
00344 bb->index, e->dest->index);
00345 fprintf (dump_file, HOST_WIDEST_INT_PRINT_DEC,
00346 (HOST_WIDEST_INT) e->count);
00347 }
00348 }
00349 }
00350
00351 if (dump_file)
00352 fprintf (dump_file, "\n%d edge counts read\n", num_edges);
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371 changes = 1;
00372 passes = 0;
00373 while (changes)
00374 {
00375 passes++;
00376 changes = 0;
00377 FOR_BB_BETWEEN (bb, EXIT_BLOCK_PTR, NULL, prev_bb)
00378 {
00379 struct bb_info *bi = BB_INFO (bb);
00380 if (! bi->count_valid)
00381 {
00382 if (bi->succ_count == 0)
00383 {
00384 edge e;
00385 edge_iterator ei;
00386 gcov_type total = 0;
00387
00388 FOR_EACH_EDGE (e, ei, bb->succs)
00389 total += e->count;
00390 bb->count = total;
00391 bi->count_valid = 1;
00392 changes = 1;
00393 }
00394 else if (bi->pred_count == 0)
00395 {
00396 edge e;
00397 edge_iterator ei;
00398 gcov_type total = 0;
00399
00400 FOR_EACH_EDGE (e, ei, bb->preds)
00401 total += e->count;
00402 bb->count = total;
00403 bi->count_valid = 1;
00404 changes = 1;
00405 }
00406 }
00407 if (bi->count_valid)
00408 {
00409 if (bi->succ_count == 1)
00410 {
00411 edge e;
00412 edge_iterator ei;
00413 gcov_type total = 0;
00414
00415
00416
00417 FOR_EACH_EDGE (e, ei, bb->succs)
00418 total += e->count;
00419
00420
00421 FOR_EACH_EDGE (e, ei, bb->succs)
00422 if (! EDGE_INFO (e)->count_valid && ! EDGE_INFO (e)->ignore)
00423 break;
00424
00425
00426 total = bb->count - total;
00427
00428 gcc_assert (e);
00429 EDGE_INFO (e)->count_valid = 1;
00430 e->count = total;
00431 bi->succ_count--;
00432
00433 BB_INFO (e->dest)->pred_count--;
00434 changes = 1;
00435 }
00436 if (bi->pred_count == 1)
00437 {
00438 edge e;
00439 edge_iterator ei;
00440 gcov_type total = 0;
00441
00442
00443
00444 FOR_EACH_EDGE (e, ei, bb->preds)
00445 total += e->count;
00446
00447
00448 FOR_EACH_EDGE (e, ei, bb->preds)
00449 if (!EDGE_INFO (e)->count_valid && !EDGE_INFO (e)->ignore)
00450 break;
00451
00452
00453 total = bb->count - total + e->count;
00454
00455 gcc_assert (e);
00456 EDGE_INFO (e)->count_valid = 1;
00457 e->count = total;
00458 bi->pred_count--;
00459
00460 BB_INFO (e->src)->succ_count--;
00461 changes = 1;
00462 }
00463 }
00464 }
00465 }
00466 if (dump_file)
00467 dump_flow_info (dump_file, dump_flags);
00468
00469 total_num_passes += passes;
00470 if (dump_file)
00471 fprintf (dump_file, "Graph solving took %d passes.\n\n", passes);
00472
00473
00474
00475 FOR_EACH_BB (bb)
00476 {
00477 gcc_assert (!BB_INFO (bb)->succ_count && !BB_INFO (bb)->pred_count);
00478 }
00479
00480
00481
00482
00483 for (i = 0; i < 20; i++)
00484 hist_br_prob[i] = 0;
00485 num_never_executed = 0;
00486 num_branches = 0;
00487
00488 FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
00489 {
00490 edge e;
00491 edge_iterator ei;
00492
00493 if (bb->count < 0)
00494 {
00495 error ("corrupted profile info: number of iterations for basic block %d thought to be %i",
00496 bb->index, (int)bb->count);
00497 bb->count = 0;
00498 }
00499 FOR_EACH_EDGE (e, ei, bb->succs)
00500 {
00501
00502
00503
00504
00505
00506 if ((e->count < 0
00507 && e->dest == EXIT_BLOCK_PTR)
00508 || (e->count > bb->count
00509 && e->dest != EXIT_BLOCK_PTR))
00510 {
00511 if (block_ends_with_call_p (bb))
00512 e->count = e->count < 0 ? 0 : bb->count;
00513 }
00514 if (e->count < 0 || e->count > bb->count)
00515 {
00516 error ("corrupted profile info: number of executions for edge %d-%d thought to be %i",
00517 e->src->index, e->dest->index,
00518 (int)e->count);
00519 e->count = bb->count / 2;
00520 }
00521 }
00522 if (bb->count)
00523 {
00524 FOR_EACH_EDGE (e, ei, bb->succs)
00525 e->probability = (e->count * REG_BR_PROB_BASE + bb->count / 2) / bb->count;
00526 if (bb->index >= NUM_FIXED_BLOCKS
00527 && block_ends_with_condjump_p (bb)
00528 && EDGE_COUNT (bb->succs) >= 2)
00529 {
00530 int prob;
00531 edge e;
00532 int index;
00533
00534
00535
00536 FOR_EACH_EDGE (e, ei, bb->succs)
00537 if (!(e->flags & (EDGE_FAKE | EDGE_FALLTHRU)))
00538 break;
00539
00540 prob = e->probability;
00541 index = prob * 20 / REG_BR_PROB_BASE;
00542
00543 if (index == 20)
00544 index = 19;
00545 hist_br_prob[index]++;
00546
00547 num_branches++;
00548 }
00549 }
00550
00551
00552
00553
00554
00555 else if (profile_status == PROFILE_ABSENT)
00556 {
00557 int total = 0;
00558
00559 FOR_EACH_EDGE (e, ei, bb->succs)
00560 if (!(e->flags & (EDGE_COMPLEX | EDGE_FAKE)))
00561 total ++;
00562 if (total)
00563 {
00564 FOR_EACH_EDGE (e, ei, bb->succs)
00565 if (!(e->flags & (EDGE_COMPLEX | EDGE_FAKE)))
00566 e->probability = REG_BR_PROB_BASE / total;
00567 else
00568 e->probability = 0;
00569 }
00570 else
00571 {
00572 total += EDGE_COUNT (bb->succs);
00573 FOR_EACH_EDGE (e, ei, bb->succs)
00574 e->probability = REG_BR_PROB_BASE / total;
00575 }
00576 if (bb->index >= NUM_FIXED_BLOCKS
00577 && block_ends_with_condjump_p (bb)
00578 && EDGE_COUNT (bb->succs) >= 2)
00579 num_branches++, num_never_executed;
00580 }
00581 }
00582 counts_to_freqs ();
00583
00584 if (dump_file)
00585 {
00586 fprintf (dump_file, "%d branches\n", num_branches);
00587 fprintf (dump_file, "%d branches never executed\n",
00588 num_never_executed);
00589 if (num_branches)
00590 for (i = 0; i < 10; i++)
00591 fprintf (dump_file, "%d%% branches in range %d-%d%%\n",
00592 (hist_br_prob[i] + hist_br_prob[19-i]) * 100 / num_branches,
00593 5 * i, 5 * i + 5);
00594
00595 total_num_branches += num_branches;
00596 total_num_never_executed += num_never_executed;
00597 for (i = 0; i < 20; i++)
00598 total_hist_br_prob[i] += hist_br_prob[i];
00599
00600 fputc ('\n', dump_file);
00601 fputc ('\n', dump_file);
00602 }
00603
00604 free_aux_for_blocks ();
00605 }
00606
00607
00608
00609
00610 static void
00611 compute_value_histograms (histogram_values values)
00612 {
00613 unsigned i, j, t, any;
00614 unsigned n_histogram_counters[GCOV_N_VALUE_COUNTERS];
00615 gcov_type *histogram_counts[GCOV_N_VALUE_COUNTERS];
00616 gcov_type *act_count[GCOV_N_VALUE_COUNTERS];
00617 gcov_type *aact_count;
00618
00619 for (t = 0; t < GCOV_N_VALUE_COUNTERS; t++)
00620 n_histogram_counters[t] = 0;
00621
00622 for (i = 0; i < VEC_length (histogram_value, values); i++)
00623 {
00624 histogram_value hist = VEC_index (histogram_value, values, i);
00625 n_histogram_counters[(int) hist->type] += hist->n_counters;
00626 }
00627
00628 any = 0;
00629 for (t = 0; t < GCOV_N_VALUE_COUNTERS; t++)
00630 {
00631 if (!n_histogram_counters[t])
00632 {
00633 histogram_counts[t] = NULL;
00634 continue;
00635 }
00636
00637 histogram_counts[t] =
00638 get_coverage_counts (COUNTER_FOR_HIST_TYPE (t),
00639 n_histogram_counters[t], NULL);
00640 if (histogram_counts[t])
00641 any = 1;
00642 act_count[t] = histogram_counts[t];
00643 }
00644 if (!any)
00645 return;
00646
00647 for (i = 0; i < VEC_length (histogram_value, values); i++)
00648 {
00649 histogram_value hist = VEC_index (histogram_value, values, i);
00650 tree stmt = hist->hvalue.stmt;
00651 stmt_ann_t ann = get_stmt_ann (stmt);
00652
00653 t = (int) hist->type;
00654
00655 aact_count = act_count[t];
00656 act_count[t] += hist->n_counters;
00657
00658 hist->hvalue.next = ann->histograms;
00659 ann->histograms = hist;
00660 hist->hvalue.counters = XNEWVEC (gcov_type, hist->n_counters);
00661 for (j = 0; j < hist->n_counters; j++)
00662 hist->hvalue.counters[j] = aact_count[j];
00663 }
00664
00665 for (t = 0; t < GCOV_N_VALUE_COUNTERS; t++)
00666 if (histogram_counts[t])
00667 free (histogram_counts[t]);
00668 }
00669
00670
00671
00672 #define BB_TO_GCOV_INDEX(bb) ((bb)->index - 1)
00673
00674
00675
00676 static void
00677 output_location (char const *file_name, int line,
00678 gcov_position_t *offset, basic_block bb)
00679 {
00680 static char const *prev_file_name;
00681 static int prev_line;
00682 bool name_differs, line_differs;
00683
00684 if (!file_name)
00685 {
00686 prev_file_name = NULL;
00687 prev_line = -1;
00688 return;
00689 }
00690
00691 name_differs = !prev_file_name || strcmp (file_name, prev_file_name);
00692 line_differs = prev_line != line;
00693
00694 if (name_differs || line_differs)
00695 {
00696 if (!*offset)
00697 {
00698 *offset = gcov_write_tag (GCOV_TAG_LINES);
00699 gcov_write_unsigned (BB_TO_GCOV_INDEX (bb));
00700 name_differs = line_differs=true;
00701 }
00702
00703
00704
00705 if (name_differs)
00706 {
00707 prev_file_name = file_name;
00708 gcov_write_unsigned (0);
00709 gcov_write_string (prev_file_name);
00710 }
00711 if (line_differs)
00712 {
00713 gcov_write_unsigned (line);
00714 prev_line = line;
00715 }
00716 }
00717 }
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735 void
00736 branch_prob (void)
00737 {
00738 basic_block bb;
00739 unsigned i;
00740 unsigned num_edges, ignored_edges;
00741 unsigned num_instrumented;
00742 struct edge_list *el;
00743 histogram_values values = NULL;
00744
00745 total_num_times_called++;
00746
00747 flow_call_edges_add (NULL);
00748 add_noreturn_fake_exit_edges ();
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759 FOR_EACH_BB (bb)
00760 {
00761 int need_exit_edge = 0, need_entry_edge = 0;
00762 int have_exit_edge = 0, have_entry_edge = 0;
00763 edge e;
00764 edge_iterator ei;
00765
00766
00767
00768
00769
00770
00771
00772 FOR_EACH_EDGE (e, ei, bb->succs)
00773 {
00774 block_stmt_iterator bsi;
00775 tree last = NULL;
00776
00777
00778
00779
00780 for (bsi = bsi_last (bb); !bsi_end_p (bsi); bsi_prev (&bsi))
00781 {
00782 last = bsi_stmt (bsi);
00783 if (EXPR_LOCUS (last))
00784 break;
00785 }
00786
00787
00788
00789
00790
00791
00792 if (last && EXPR_LOCUS (last)
00793 && e->goto_locus
00794 && !single_succ_p (bb)
00795 #ifdef USE_MAPPED_LOCATION
00796 && (LOCATION_FILE (e->goto_locus)
00797 != LOCATION_FILE (EXPR_LOCATION (last))
00798 || (LOCATION_LINE (e->goto_locus)
00799 != LOCATION_LINE (EXPR_LOCATION (last)))))
00800 #else
00801 && (e->goto_locus->file != EXPR_LOCUS (last)->file
00802 || (e->goto_locus->line != EXPR_LOCUS (last)->line)))
00803 #endif
00804 {
00805 basic_block new = split_edge (e);
00806 single_succ_edge (new)->goto_locus = e->goto_locus;
00807 }
00808 if ((e->flags & (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL))
00809 && e->dest != EXIT_BLOCK_PTR)
00810 need_exit_edge = 1;
00811 if (e->dest == EXIT_BLOCK_PTR)
00812 have_exit_edge = 1;
00813 }
00814 FOR_EACH_EDGE (e, ei, bb->preds)
00815 {
00816 if ((e->flags & (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL))
00817 && e->src != ENTRY_BLOCK_PTR)
00818 need_entry_edge = 1;
00819 if (e->src == ENTRY_BLOCK_PTR)
00820 have_entry_edge = 1;
00821 }
00822
00823 if (need_exit_edge && !have_exit_edge)
00824 {
00825 if (dump_file)
00826 fprintf (dump_file, "Adding fake exit edge to bb %i\n",
00827 bb->index);
00828 make_edge (bb, EXIT_BLOCK_PTR, EDGE_FAKE);
00829 }
00830 if (need_entry_edge && !have_entry_edge)
00831 {
00832 if (dump_file)
00833 fprintf (dump_file, "Adding fake entry edge to bb %i\n",
00834 bb->index);
00835 make_edge (ENTRY_BLOCK_PTR, bb, EDGE_FAKE);
00836 }
00837 }
00838
00839 el = create_edge_list ();
00840 num_edges = NUM_EDGES (el);
00841 alloc_aux_for_edges (sizeof (struct edge_info));
00842
00843
00844 compact_blocks ();
00845
00846 ignored_edges = 0;
00847 for (i = 0 ; i < num_edges ; i++)
00848 {
00849 edge e = INDEX_EDGE (el, i);
00850 e->count = 0;
00851
00852
00853 if ((e->flags & (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL))
00854 && e->src != ENTRY_BLOCK_PTR && e->dest != EXIT_BLOCK_PTR)
00855 {
00856 EDGE_INFO (e)->ignore = 1;
00857 ignored_edges++;
00858 }
00859 }
00860
00861
00862
00863
00864
00865 find_spanning_tree (el);
00866
00867
00868
00869 for (num_instrumented = i = 0; i < num_edges; i++)
00870 {
00871 edge e = INDEX_EDGE (el, i);
00872 struct edge_info *inf = EDGE_INFO (e);
00873
00874 if (inf->ignore || inf->on_tree)
00875 ;
00876 else if (e->flags & EDGE_FAKE)
00877 {
00878 inf->ignore = 1;
00879 ignored_edges++;
00880 }
00881 else
00882 num_instrumented++;
00883 }
00884
00885 total_num_blocks += n_basic_blocks;
00886 if (dump_file)
00887 fprintf (dump_file, "%d basic blocks\n", n_basic_blocks);
00888
00889 total_num_edges += num_edges;
00890 if (dump_file)
00891 fprintf (dump_file, "%d edges\n", num_edges);
00892
00893 total_num_edges_ignored += ignored_edges;
00894 if (dump_file)
00895 fprintf (dump_file, "%d ignored edges\n", ignored_edges);
00896
00897
00898
00899
00900
00901 if (coverage_begin_output ())
00902 {
00903 gcov_position_t offset;
00904
00905 offset = gcov_write_tag (GCOV_TAG_BLOCKS);
00906 for (i = 0; i != (unsigned) (n_basic_blocks); i++)
00907 gcov_write_unsigned (0);
00908 gcov_write_length (offset);
00909 }
00910
00911
00912
00913
00914 ENTRY_BLOCK_PTR->index = 1;
00915 EXIT_BLOCK_PTR->index = last_basic_block;
00916
00917
00918 if (coverage_begin_output ())
00919 {
00920 gcov_position_t offset;
00921
00922 FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb)
00923 {
00924 edge e;
00925 edge_iterator ei;
00926
00927 offset = gcov_write_tag (GCOV_TAG_ARCS);
00928 gcov_write_unsigned (BB_TO_GCOV_INDEX (bb));
00929
00930 FOR_EACH_EDGE (e, ei, bb->succs)
00931 {
00932 struct edge_info *i = EDGE_INFO (e);
00933 if (!i->ignore)
00934 {
00935 unsigned flag_bits = 0;
00936
00937 if (i->on_tree)
00938 flag_bits |= GCOV_ARC_ON_TREE;
00939 if (e->flags & EDGE_FAKE)
00940 flag_bits |= GCOV_ARC_FAKE;
00941 if (e->flags & EDGE_FALLTHRU)
00942 flag_bits |= GCOV_ARC_FALLTHROUGH;
00943
00944
00945 if (e->flags & (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE)
00946 && e->src->next_bb == e->dest)
00947 flag_bits |= GCOV_ARC_FALLTHROUGH;
00948
00949 gcov_write_unsigned (BB_TO_GCOV_INDEX (e->dest));
00950 gcov_write_unsigned (flag_bits);
00951 }
00952 }
00953
00954 gcov_write_length (offset);
00955 }
00956 }
00957
00958
00959 if (coverage_begin_output ())
00960 {
00961 gcov_position_t offset;
00962
00963
00964 output_location (NULL, 0, NULL, NULL);
00965
00966 FOR_EACH_BB (bb)
00967 {
00968 block_stmt_iterator bsi;
00969
00970 offset = 0;
00971
00972 if (bb == ENTRY_BLOCK_PTR->next_bb)
00973 {
00974 expanded_location curr_location =
00975 expand_location (DECL_SOURCE_LOCATION (current_function_decl));
00976 output_location (curr_location.file, curr_location.line,
00977 &offset, bb);
00978 }
00979
00980 for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
00981 {
00982 tree stmt = bsi_stmt (bsi);
00983 if (EXPR_HAS_LOCATION (stmt))
00984 output_location (EXPR_FILENAME (stmt), EXPR_LINENO (stmt),
00985 &offset, bb);
00986 }
00987
00988
00989
00990 if (single_succ_p (bb) && single_succ_edge (bb)->goto_locus)
00991 {
00992
00993 source_locus curr_location = single_succ_edge (bb)->goto_locus;
00994
00995 #ifdef USE_MAPPED_LOCATION
00996 output_location (LOCATION_FILE (curr_location),
00997 LOCATION_LINE (curr_location), &offset, bb);
00998 #else
00999 output_location (curr_location->file, curr_location->line,
01000 &offset, bb);
01001 #endif
01002 }
01003
01004 if (offset)
01005 {
01006
01007 gcov_write_unsigned (0);
01008 gcov_write_string (NULL);
01009 gcov_write_length (offset);
01010 }
01011 }
01012 }
01013
01014 ENTRY_BLOCK_PTR->index = ENTRY_BLOCK;
01015 EXIT_BLOCK_PTR->index = EXIT_BLOCK;
01016 #undef BB_TO_GCOV_INDEX
01017
01018 if (flag_profile_values)
01019 find_values_to_profile (&values);
01020
01021 if (flag_branch_probabilities)
01022 {
01023 compute_branch_probabilities ();
01024 if (flag_profile_values)
01025 compute_value_histograms (values);
01026 }
01027
01028 remove_fake_edges ();
01029
01030
01031 if (profile_arc_flag
01032 && coverage_counter_alloc (GCOV_COUNTER_ARCS, num_instrumented))
01033 {
01034 unsigned n_instrumented;
01035
01036 profile_hooks->init_edge_profiler ();
01037
01038 n_instrumented = instrument_edges (el);
01039
01040 gcc_assert (n_instrumented == num_instrumented);
01041
01042 if (flag_profile_values)
01043 instrument_values (values);
01044
01045
01046 bsi_commit_edge_inserts ();
01047 }
01048
01049 free_aux_for_edges ();
01050
01051 VEC_free (histogram_value, heap, values);
01052 free_edge_list (el);
01053 if (flag_branch_probabilities)
01054 profile_status = PROFILE_READ;
01055 coverage_end_function ();
01056 }
01057
01058
01059
01060
01061 static basic_block
01062 find_group (basic_block bb)
01063 {
01064 basic_block group = bb, bb1;
01065
01066 while ((basic_block) group->aux != group)
01067 group = (basic_block) group->aux;
01068
01069
01070 while ((basic_block) bb->aux != group)
01071 {
01072 bb1 = (basic_block) bb->aux;
01073 bb->aux = (void *) group;
01074 bb = bb1;
01075 }
01076 return group;
01077 }
01078
01079 static void
01080 union_groups (basic_block bb1, basic_block bb2)
01081 {
01082 basic_block bb1g = find_group (bb1);
01083 basic_block bb2g = find_group (bb2);
01084
01085
01086
01087 gcc_assert (bb1g != bb2g);
01088
01089 bb1g->aux = bb2g;
01090 }
01091
01092
01093
01094
01095
01096
01097
01098
01099 static void
01100 find_spanning_tree (struct edge_list *el)
01101 {
01102 int i;
01103 int num_edges = NUM_EDGES (el);
01104 basic_block bb;
01105
01106
01107 FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
01108 bb->aux = bb;
01109
01110
01111 union_groups (EXIT_BLOCK_PTR, ENTRY_BLOCK_PTR);
01112
01113
01114
01115
01116 for (i = 0; i < num_edges; i++)
01117 {
01118 edge e = INDEX_EDGE (el, i);
01119 if (((e->flags & (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL | EDGE_FAKE))
01120 || e->dest == EXIT_BLOCK_PTR)
01121 && !EDGE_INFO (e)->ignore
01122 && (find_group (e->src) != find_group (e->dest)))
01123 {
01124 if (dump_file)
01125 fprintf (dump_file, "Abnormal edge %d to %d put to tree\n",
01126 e->src->index, e->dest->index);
01127 EDGE_INFO (e)->on_tree = 1;
01128 union_groups (e->src, e->dest);
01129 }
01130 }
01131
01132
01133 for (i = 0; i < num_edges; i++)
01134 {
01135 edge e = INDEX_EDGE (el, i);
01136 if (EDGE_CRITICAL_P (e) && !EDGE_INFO (e)->ignore
01137 && find_group (e->src) != find_group (e->dest))
01138 {
01139 if (dump_file)
01140 fprintf (dump_file, "Critical edge %d to %d put to tree\n",
01141 e->src->index, e->dest->index);
01142 EDGE_INFO (e)->on_tree = 1;
01143 union_groups (e->src, e->dest);
01144 }
01145 }
01146
01147
01148 for (i = 0; i < num_edges; i++)
01149 {
01150 edge e = INDEX_EDGE (el, i);
01151 if (!EDGE_INFO (e)->ignore
01152 && find_group (e->src) != find_group (e->dest))
01153 {
01154 if (dump_file)
01155 fprintf (dump_file, "Normal edge %d to %d put to tree\n",
01156 e->src->index, e->dest->index);
01157 EDGE_INFO (e)->on_tree = 1;
01158 union_groups (e->src, e->dest);
01159 }
01160 }
01161
01162 FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
01163 bb->aux = NULL;
01164 }
01165
01166
01167
01168 void
01169 init_branch_prob (void)
01170 {
01171 int i;
01172
01173 total_num_blocks = 0;
01174 total_num_edges = 0;
01175 total_num_edges_ignored = 0;
01176 total_num_edges_instrumented = 0;
01177 total_num_blocks_created = 0;
01178 total_num_passes = 0;
01179 total_num_times_called = 0;
01180 total_num_branches = 0;
01181 total_num_never_executed = 0;
01182 for (i = 0; i < 20; i++)
01183 total_hist_br_prob[i] = 0;
01184 }
01185
01186
01187
01188
01189 void
01190 end_branch_prob (void)
01191 {
01192 if (dump_file)
01193 {
01194 fprintf (dump_file, "\n");
01195 fprintf (dump_file, "Total number of blocks: %d\n",
01196 total_num_blocks);
01197 fprintf (dump_file, "Total number of edges: %d\n", total_num_edges);
01198 fprintf (dump_file, "Total number of ignored edges: %d\n",
01199 total_num_edges_ignored);
01200 fprintf (dump_file, "Total number of instrumented edges: %d\n",
01201 total_num_edges_instrumented);
01202 fprintf (dump_file, "Total number of blocks created: %d\n",
01203 total_num_blocks_created);
01204 fprintf (dump_file, "Total number of graph solution passes: %d\n",
01205 total_num_passes);
01206 if (total_num_times_called != 0)
01207 fprintf (dump_file, "Average number of graph solution passes: %d\n",
01208 (total_num_passes + (total_num_times_called >> 1))
01209 / total_num_times_called);
01210 fprintf (dump_file, "Total number of branches: %d\n",
01211 total_num_branches);
01212 fprintf (dump_file, "Total number of branches never executed: %d\n",
01213 total_num_never_executed);
01214 if (total_num_branches)
01215 {
01216 int i;
01217
01218 for (i = 0; i < 10; i++)
01219 fprintf (dump_file, "%d%% branches in range %d-%d%%\n",
01220 (total_hist_br_prob[i] + total_hist_br_prob[19-i]) * 100
01221 / total_num_branches, 5*i, 5*i+5);
01222 }
01223 }
01224 }
01225
01226
01227
01228 void
01229 tree_register_profile_hooks (void)
01230 {
01231 gcc_assert (ir_type ());
01232 profile_hooks = &tree_profile_hooks;
01233 }
01234