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
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074 #include "config.h"
00075 #include "system.h"
00076 #include "rtl.h"
00077 #include "tree.h"
00078 #include "flags.h"
00079 #include "insn-config.h"
00080 #include "output.h"
00081 #include "regs.h"
00082 #include "expr.h"
00083 #include "function.h"
00084 #include "toplev.h"
00085 #include "ggc.h"
00086 #include "hard-reg-set.h"
00087 #include "basic-block.h"
00088 #include "gcov-io.h"
00089 #include "target.h"
00090 #include "profile.h"
00091 #include "libfuncs.h"
00092 #include "langhooks.h"
00093 #ifdef SGI_MONGOOSE
00094
00095 #include "defaults.h"
00096 #endif
00097
00098
00099 struct edge_info {
00100 unsigned int count_valid : 1;
00101
00102
00103 unsigned int on_tree : 1;
00104
00105
00106
00107 unsigned int ignore : 1;
00108 };
00109
00110 struct bb_info {
00111 unsigned int count_valid : 1;
00112
00113
00114 gcov_type succ_count;
00115 gcov_type pred_count;
00116 };
00117
00118 #define EDGE_INFO(e) ((struct edge_info *) (e)->aux)
00119 #define BB_INFO(b) ((struct bb_info *) (b)->aux)
00120
00121
00122
00123 #define BB_TO_GCOV_INDEX(bb) ((bb) == ENTRY_BLOCK_PTR ? 0 \
00124 : ((bb) == EXIT_BLOCK_PTR \
00125 ? last_basic_block + 1 : (bb)->index + 1))
00126
00127
00128
00129 struct profile_info profile_info;
00130
00131
00132
00133 static FILE *bbg_file;
00134
00135
00136
00137 static FILE *da_file;
00138 static char *da_file_name;
00139
00140
00141 static FILE *bb_file;
00142
00143
00144
00145 static char *last_bb_file_name;
00146
00147
00148
00149
00150 static int total_num_blocks;
00151 static int total_num_edges;
00152 static int total_num_edges_ignored;
00153 static int total_num_edges_instrumented;
00154 static int total_num_blocks_created;
00155 static int total_num_passes;
00156 static int total_num_times_called;
00157 static int total_hist_br_prob[20];
00158 static int total_num_never_executed;
00159 static int total_num_branches;
00160
00161
00162 static void find_spanning_tree PARAMS ((struct edge_list *));
00163 static void init_edge_profiler PARAMS ((void));
00164 static rtx gen_edge_profiler PARAMS ((int));
00165 static void instrument_edges PARAMS ((struct edge_list *));
00166 static void output_gcov_string PARAMS ((const char *, long));
00167 static void compute_branch_probabilities PARAMS ((void));
00168 static gcov_type * get_exec_counts PARAMS ((void));
00169 static long compute_checksum PARAMS ((void));
00170 static basic_block find_group PARAMS ((basic_block));
00171 static void union_groups PARAMS ((basic_block, basic_block));
00172
00173
00174
00175 static int need_func_profiler = 0;
00176
00177
00178
00179
00180
00181
00182 static void
00183 instrument_edges (el)
00184 struct edge_list *el;
00185 {
00186 int num_instr_edges = 0;
00187 int num_edges = NUM_EDGES (el);
00188 basic_block bb;
00189 remove_fake_edges ();
00190
00191 FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
00192 {
00193 edge e = bb->succ;
00194 while (e)
00195 {
00196 struct edge_info *inf = EDGE_INFO (e);
00197 if (!inf->ignore && !inf->on_tree)
00198 {
00199 if (e->flags & EDGE_ABNORMAL)
00200 abort ();
00201 if (rtl_dump_file)
00202 fprintf (rtl_dump_file, "Edge %d to %d instrumented%s\n",
00203 e->src->index, e->dest->index,
00204 EDGE_CRITICAL_P (e) ? " (and split)" : "");
00205 need_func_profiler = 1;
00206 insert_insn_on_edge (
00207 gen_edge_profiler (total_num_edges_instrumented
00208 + num_instr_edges++), e);
00209 }
00210 e = e->succ_next;
00211 }
00212 }
00213
00214 profile_info.count_edges_instrumented_now = num_instr_edges;
00215 total_num_edges_instrumented += num_instr_edges;
00216 profile_info.count_instrumented_edges = total_num_edges_instrumented;
00217
00218 total_num_blocks_created += num_edges;
00219 if (rtl_dump_file)
00220 fprintf (rtl_dump_file, "%d edges instrumented\n", num_instr_edges);
00221
00222 commit_edge_insertions_watch_calls ();
00223 }
00224
00225
00226
00227 static void
00228 output_gcov_string (string, delimiter)
00229 const char *string;
00230 long delimiter;
00231 {
00232 size_t temp;
00233
00234
00235 __write_long (delimiter, bb_file, 4);
00236
00237
00238 temp = strlen (string) + 1;
00239 fwrite (string, temp, 1, bb_file);
00240
00241
00242 temp = temp & 0x3;
00243 if (temp)
00244 {
00245 char c[4];
00246
00247 c[0] = c[1] = c[2] = c[3] = 0;
00248 fwrite (c, sizeof (char), 4 - temp, bb_file);
00249 }
00250
00251
00252
00253 __write_long (delimiter, bb_file, 4);
00254 }
00255
00256
00257
00258
00259
00260 static gcov_type *
00261 get_exec_counts ()
00262 {
00263 int num_edges = 0;
00264 basic_block bb;
00265 int okay = 1, i;
00266 int mismatch = 0;
00267 gcov_type *profile;
00268 char *function_name_buffer;
00269 int function_name_buffer_len;
00270 gcov_type max_counter_in_run;
00271 const char *name = IDENTIFIER_POINTER
00272 (DECL_ASSEMBLER_NAME (current_function_decl));
00273
00274 profile_info.max_counter_in_program = 0;
00275 profile_info.count_profiles_merged = 0;
00276
00277
00278 if (!da_file)
00279 return 0;
00280
00281
00282
00283 FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
00284 {
00285 edge e;
00286 for (e = bb->succ; e; e = e->succ_next)
00287 if (!EDGE_INFO (e)->ignore && !EDGE_INFO (e)->on_tree)
00288 num_edges++;
00289 }
00290
00291
00292
00293 profile = xmalloc (sizeof (gcov_type) * num_edges);
00294 rewind (da_file);
00295 function_name_buffer_len = strlen (name) + 1;
00296 function_name_buffer = xmalloc (function_name_buffer_len + 1);
00297
00298 for (i = 0; i < num_edges; i++)
00299 profile[i] = 0;
00300
00301 while (1)
00302 {
00303 long magic, extra_bytes;
00304 long func_count;
00305 int i;
00306
00307 if (__read_long (&magic, da_file, 4) != 0)
00308 break;
00309
00310 if (magic != -123)
00311 {
00312 okay = 0;
00313 break;
00314 }
00315
00316 if (__read_long (&func_count, da_file, 4) != 0)
00317 {
00318 okay = 0;
00319 break;
00320 }
00321
00322 if (__read_long (&extra_bytes, da_file, 4) != 0)
00323 {
00324 okay = 0;
00325 break;
00326 }
00327
00328 fseek (da_file, 4 + 8, SEEK_CUR);
00329
00330
00331 __read_gcov_type (&max_counter_in_run, da_file, 8);
00332
00333
00334 fseek (da_file, extra_bytes - (4 + 8 + 8), SEEK_CUR);
00335
00336 for (i = 0; i < func_count; i++)
00337 {
00338 long arc_count;
00339 long chksum;
00340 int j;
00341
00342 if (__read_gcov_string
00343 (function_name_buffer, function_name_buffer_len, da_file,
00344 -1) != 0)
00345 {
00346 okay = 0;
00347 break;
00348 }
00349
00350 if (__read_long (&chksum, da_file, 4) != 0)
00351 {
00352 okay = 0;
00353 break;
00354 }
00355
00356 if (__read_long (&arc_count, da_file, 4) != 0)
00357 {
00358 okay = 0;
00359 break;
00360 }
00361
00362 if (strcmp (function_name_buffer, name) != 0)
00363 {
00364
00365 if (fseek (da_file, arc_count * 8, SEEK_CUR) < 0)
00366 {
00367 okay = 0;
00368 break;
00369 }
00370 }
00371 else if (arc_count != num_edges
00372 || chksum != profile_info.current_function_cfg_checksum)
00373 okay = 0, mismatch = 1;
00374 else
00375 {
00376 gcov_type tmp;
00377
00378 profile_info.max_counter_in_program += max_counter_in_run;
00379 profile_info.count_profiles_merged++;
00380
00381 for (j = 0; j < arc_count; j++)
00382 if (__read_gcov_type (&tmp, da_file, 8) != 0)
00383 {
00384 okay = 0;
00385 break;
00386 }
00387 else
00388 {
00389 profile[j] += tmp;
00390 }
00391 }
00392 }
00393
00394 if (!okay)
00395 break;
00396
00397 }
00398
00399 free (function_name_buffer);
00400
00401 if (!okay)
00402 {
00403 if (mismatch)
00404 error
00405 ("Profile does not match flowgraph of function %s (out of date?)",
00406 current_function_name);
00407 else
00408 error (".da file corrupted");
00409 free (profile);
00410 return 0;
00411 }
00412 if (rtl_dump_file)
00413 {
00414 fprintf(rtl_dump_file, "Merged %i profiles with maximal count %i.\n",
00415 profile_info.count_profiles_merged,
00416 (int)profile_info.max_counter_in_program);
00417 }
00418
00419 return profile;
00420 }
00421
00422
00423
00424
00425
00426 static void
00427 compute_branch_probabilities ()
00428 {
00429 basic_block bb;
00430 int i;
00431 int num_edges = 0;
00432 int changes;
00433 int passes;
00434 int hist_br_prob[20];
00435 int num_never_executed;
00436 int num_branches;
00437 gcov_type *exec_counts = get_exec_counts ();
00438 int exec_counts_pos = 0;
00439
00440
00441
00442 alloc_aux_for_blocks (sizeof (struct bb_info));
00443 FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
00444 {
00445 edge e;
00446
00447 for (e = bb->succ; e; e = e->succ_next)
00448 if (!EDGE_INFO (e)->ignore)
00449 BB_INFO (bb)->succ_count++;
00450 for (e = bb->pred; e; e = e->pred_next)
00451 if (!EDGE_INFO (e)->ignore)
00452 BB_INFO (bb)->pred_count++;
00453 }
00454
00455
00456 BB_INFO (EXIT_BLOCK_PTR)->succ_count = 2;
00457 BB_INFO (ENTRY_BLOCK_PTR)->pred_count = 2;
00458
00459
00460
00461
00462
00463
00464
00465 FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
00466 {
00467 edge e;
00468 for (e = bb->succ; e; e = e->succ_next)
00469 if (!EDGE_INFO (e)->ignore && !EDGE_INFO (e)->on_tree)
00470 {
00471 num_edges++;
00472 if (exec_counts)
00473 {
00474 e->count = exec_counts[exec_counts_pos++];
00475 }
00476 else
00477 e->count = 0;
00478
00479 EDGE_INFO (e)->count_valid = 1;
00480 BB_INFO (bb)->succ_count--;
00481 BB_INFO (e->dest)->pred_count--;
00482 if (rtl_dump_file)
00483 {
00484 fprintf (rtl_dump_file, "\nRead edge from %i to %i, count:",
00485 bb->index, e->dest->index);
00486 fprintf (rtl_dump_file, HOST_WIDEST_INT_PRINT_DEC,
00487 (HOST_WIDEST_INT) e->count);
00488 }
00489 }
00490 }
00491
00492 if (rtl_dump_file)
00493 fprintf (rtl_dump_file, "\n%d edge counts read\n", num_edges);
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512 changes = 1;
00513 passes = 0;
00514 while (changes)
00515 {
00516 passes++;
00517 changes = 0;
00518 FOR_BB_BETWEEN (bb, EXIT_BLOCK_PTR, NULL, prev_bb)
00519 {
00520 struct bb_info *bi = BB_INFO (bb);
00521 if (! bi->count_valid)
00522 {
00523 if (bi->succ_count == 0)
00524 {
00525 edge e;
00526 gcov_type total = 0;
00527
00528 for (e = bb->succ; e; e = e->succ_next)
00529 total += e->count;
00530 bb->count = total;
00531 bi->count_valid = 1;
00532 changes = 1;
00533 }
00534 else if (bi->pred_count == 0)
00535 {
00536 edge e;
00537 gcov_type total = 0;
00538
00539 for (e = bb->pred; e; e = e->pred_next)
00540 total += e->count;
00541 bb->count = total;
00542 bi->count_valid = 1;
00543 changes = 1;
00544 }
00545 }
00546 if (bi->count_valid)
00547 {
00548 if (bi->succ_count == 1)
00549 {
00550 edge e;
00551 gcov_type total = 0;
00552
00553
00554
00555 for (e = bb->succ; e; e = e->succ_next)
00556 total += e->count;
00557
00558
00559 for (e = bb->succ; e; e = e->succ_next)
00560 if (! EDGE_INFO (e)->count_valid && ! EDGE_INFO (e)->ignore)
00561 break;
00562
00563
00564 total = bb->count - total;
00565
00566 if (! e)
00567 abort ();
00568 EDGE_INFO (e)->count_valid = 1;
00569 e->count = total;
00570 bi->succ_count--;
00571
00572 BB_INFO (e->dest)->pred_count--;
00573 changes = 1;
00574 }
00575 if (bi->pred_count == 1)
00576 {
00577 edge e;
00578 gcov_type total = 0;
00579
00580
00581
00582 for (e = bb->pred; e; e = e->pred_next)
00583 total += e->count;
00584
00585
00586 for (e = bb->pred; e; e = e->pred_next)
00587 if (! EDGE_INFO (e)->count_valid && ! EDGE_INFO (e)->ignore)
00588 break;
00589
00590
00591 total = bb->count - total + e->count;
00592
00593 if (! e)
00594 abort ();
00595 EDGE_INFO (e)->count_valid = 1;
00596 e->count = total;
00597 bi->pred_count--;
00598
00599 BB_INFO (e->src)->succ_count--;
00600 changes = 1;
00601 }
00602 }
00603 }
00604 }
00605 if (rtl_dump_file)
00606 dump_flow_info (rtl_dump_file);
00607
00608 total_num_passes += passes;
00609 if (rtl_dump_file)
00610 fprintf (rtl_dump_file, "Graph solving took %d passes.\n\n", passes);
00611
00612
00613
00614 FOR_EACH_BB (bb)
00615 {
00616 if (BB_INFO (bb)->succ_count || BB_INFO (bb)->pred_count)
00617 abort ();
00618 }
00619
00620
00621
00622
00623 for (i = 0; i < 20; i++)
00624 hist_br_prob[i] = 0;
00625 num_never_executed = 0;
00626 num_branches = 0;
00627
00628 FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
00629 {
00630 edge e;
00631 gcov_type total;
00632 rtx note;
00633
00634 total = bb->count;
00635 if (total)
00636 {
00637 for (e = bb->succ; e; e = e->succ_next)
00638 {
00639 e->probability = (e->count * REG_BR_PROB_BASE + total / 2) / total;
00640 if (e->probability < 0 || e->probability > REG_BR_PROB_BASE)
00641 {
00642 error ("corrupted profile info: prob for %d-%d thought to be %d",
00643 e->src->index, e->dest->index, e->probability);
00644 e->probability = REG_BR_PROB_BASE / 2;
00645 }
00646 }
00647 if (bb->index >= 0
00648 && any_condjump_p (bb->end)
00649 && bb->succ->succ_next)
00650 {
00651 int prob;
00652 edge e;
00653 int index;
00654
00655
00656
00657 for (e = bb->succ; e->flags & (EDGE_FAKE | EDGE_FALLTHRU);
00658 e = e->succ_next)
00659 continue;
00660
00661 prob = e->probability;
00662 index = prob * 20 / REG_BR_PROB_BASE;
00663
00664 if (index == 20)
00665 index = 19;
00666 hist_br_prob[index]++;
00667
00668 note = find_reg_note (bb->end, REG_BR_PROB, 0);
00669
00670
00671 if (note)
00672 XEXP (note, 0) = GEN_INT (prob);
00673 else
00674 REG_NOTES (bb->end)
00675 = gen_rtx_EXPR_LIST (REG_BR_PROB, GEN_INT (prob),
00676 REG_NOTES (bb->end));
00677 num_branches++;
00678 }
00679 }
00680
00681
00682
00683
00684 else
00685 {
00686 for (e = bb->succ; e; e = e->succ_next)
00687 if (!(e->flags & (EDGE_COMPLEX | EDGE_FAKE)))
00688 total ++;
00689 if (total)
00690 {
00691 for (e = bb->succ; e; e = e->succ_next)
00692 if (!(e->flags & (EDGE_COMPLEX | EDGE_FAKE)))
00693 e->probability = REG_BR_PROB_BASE / total;
00694 else
00695 e->probability = 0;
00696 }
00697 else
00698 {
00699 for (e = bb->succ; e; e = e->succ_next)
00700 total ++;
00701 for (e = bb->succ; e; e = e->succ_next)
00702 e->probability = REG_BR_PROB_BASE / total;
00703 }
00704 if (bb->index >= 0
00705 && any_condjump_p (bb->end)
00706 && bb->succ->succ_next)
00707 num_branches++, num_never_executed;
00708 }
00709 }
00710
00711 if (rtl_dump_file)
00712 {
00713 fprintf (rtl_dump_file, "%d branches\n", num_branches);
00714 fprintf (rtl_dump_file, "%d branches never executed\n",
00715 num_never_executed);
00716 if (num_branches)
00717 for (i = 0; i < 10; i++)
00718 fprintf (rtl_dump_file, "%d%% branches in range %d-%d%%\n",
00719 (hist_br_prob[i] + hist_br_prob[19-i]) * 100 / num_branches,
00720 5 * i, 5 * i + 5);
00721
00722 total_num_branches += num_branches;
00723 total_num_never_executed += num_never_executed;
00724 for (i = 0; i < 20; i++)
00725 total_hist_br_prob[i] += hist_br_prob[i];
00726
00727 fputc ('\n', rtl_dump_file);
00728 fputc ('\n', rtl_dump_file);
00729 }
00730
00731 free_aux_for_blocks ();
00732 if (exec_counts)
00733 free (exec_counts);
00734 }
00735
00736
00737
00738 #define CHSUM_HASH 500000003
00739 #define CHSUM_SHIFT 2
00740
00741 static long
00742 compute_checksum ()
00743 {
00744 long chsum = 0;
00745 basic_block bb;
00746
00747 FOR_EACH_BB (bb)
00748 {
00749 edge e;
00750
00751 for (e = bb->succ; e; e = e->succ_next)
00752 {
00753 chsum = ((chsum << CHSUM_SHIFT) + (BB_TO_GCOV_INDEX (e->dest) + 1)) % CHSUM_HASH;
00754 }
00755
00756 chsum = (chsum << CHSUM_SHIFT) % CHSUM_HASH;
00757 }
00758
00759 return chsum;
00760 }
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778 void
00779 branch_prob ()
00780 {
00781 basic_block bb;
00782 int i;
00783 int num_edges, ignored_edges;
00784 struct edge_list *el;
00785 const char *name = IDENTIFIER_POINTER
00786 (DECL_ASSEMBLER_NAME (current_function_decl));
00787
00788 profile_info.current_function_cfg_checksum = compute_checksum ();
00789
00790 if (rtl_dump_file)
00791 fprintf (rtl_dump_file, "CFG checksum is %ld\n",
00792 profile_info.current_function_cfg_checksum);
00793
00794
00795 if (flag_test_coverage)
00796 output_gcov_string (name, (long) -2);
00797
00798 total_num_times_called++;
00799
00800 flow_call_edges_add (NULL);
00801 add_noreturn_fake_exit_edges ();
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812 FOR_EACH_BB (bb)
00813 {
00814 int need_exit_edge = 0, need_entry_edge = 0;
00815 int have_exit_edge = 0, have_entry_edge = 0;
00816 rtx insn;
00817 edge e;
00818
00819
00820
00821
00822
00823 for (insn = bb->head; insn != NEXT_INSN (bb->end);
00824 insn = NEXT_INSN (insn))
00825 {
00826 if (GET_CODE (insn) == CALL_INSN
00827 && find_reg_note (insn, REG_SETJMP, NULL))
00828 {
00829 if (GET_CODE (bb->head) == CODE_LABEL
00830 || insn != NEXT_INSN (bb->head))
00831 {
00832 e = split_block (bb, PREV_INSN (insn));
00833 make_edge (ENTRY_BLOCK_PTR, e->dest, EDGE_FAKE);
00834 break;
00835 }
00836 else
00837 {
00838
00839
00840 if (bb == ENTRY_BLOCK_PTR)
00841 abort ();
00842 make_edge (ENTRY_BLOCK_PTR, bb, EDGE_FAKE);
00843 }
00844 }
00845 }
00846
00847 for (e = bb->succ; e; e = e->succ_next)
00848 {
00849 if ((e->flags & (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL))
00850 && e->dest != EXIT_BLOCK_PTR)
00851 need_exit_edge = 1;
00852 if (e->dest == EXIT_BLOCK_PTR)
00853 have_exit_edge = 1;
00854 }
00855 for (e = bb->pred; e; e = e->pred_next)
00856 {
00857 if ((e->flags & (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL))
00858 && e->src != ENTRY_BLOCK_PTR)
00859 need_entry_edge = 1;
00860 if (e->src == ENTRY_BLOCK_PTR)
00861 have_entry_edge = 1;
00862 }
00863
00864 if (need_exit_edge && !have_exit_edge)
00865 {
00866 if (rtl_dump_file)
00867 fprintf (rtl_dump_file, "Adding fake exit edge to bb %i\n",
00868 bb->index);
00869 make_edge (bb, EXIT_BLOCK_PTR, EDGE_FAKE);
00870 }
00871 if (need_entry_edge && !have_entry_edge)
00872 {
00873 if (rtl_dump_file)
00874 fprintf (rtl_dump_file, "Adding fake entry edge to bb %i\n",
00875 bb->index);
00876 make_edge (ENTRY_BLOCK_PTR, bb, EDGE_FAKE);
00877 }
00878 }
00879
00880 el = create_edge_list ();
00881 num_edges = NUM_EDGES (el);
00882 alloc_aux_for_edges (sizeof (struct edge_info));
00883
00884
00885 compact_blocks ();
00886
00887 ignored_edges = 0;
00888 for (i = 0 ; i < num_edges ; i++)
00889 {
00890 edge e = INDEX_EDGE (el, i);
00891 e->count = 0;
00892
00893
00894 if ((e->flags & (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL))
00895 && e->src != ENTRY_BLOCK_PTR && e->dest != EXIT_BLOCK_PTR)
00896 {
00897 EDGE_INFO (e)->ignore = 1;
00898 ignored_edges++;
00899 }
00900 }
00901
00902 #ifdef ENABLE_CHECKING
00903 verify_flow_info ();
00904 #endif
00905
00906
00907
00908 if (flag_test_coverage)
00909 {
00910 FOR_EACH_BB (bb)
00911 {
00912 rtx insn = bb->head;
00913 static int ignore_next_note = 0;
00914
00915
00916
00917 insn = prev_nonnote_insn (insn);
00918 if (!insn)
00919 insn = get_insns ();
00920 else
00921 insn = NEXT_INSN (insn);
00922
00923
00924
00925 __write_long (0, bb_file, 4);
00926
00927 while (insn != bb->end)
00928 {
00929 if (GET_CODE (insn) == NOTE)
00930 {
00931
00932
00933
00934
00935 if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_REPEATED_LINE_NUMBER)
00936 ignore_next_note = 1;
00937 else if (NOTE_LINE_NUMBER (insn) > 0)
00938 {
00939 if (ignore_next_note)
00940 ignore_next_note = 0;
00941 else
00942 {
00943
00944
00945 if (! last_bb_file_name
00946 || strcmp (NOTE_SOURCE_FILE (insn),
00947 last_bb_file_name))
00948 {
00949 if (last_bb_file_name)
00950 free (last_bb_file_name);
00951 last_bb_file_name
00952 = xstrdup (NOTE_SOURCE_FILE (insn));
00953 output_gcov_string (NOTE_SOURCE_FILE (insn),
00954 (long)-1);
00955 }
00956
00957
00958
00959
00960 __write_long (NOTE_LINE_NUMBER (insn), bb_file, 4);
00961 }
00962 }
00963 }
00964 insn = NEXT_INSN (insn);
00965 }
00966 }
00967 __write_long (0, bb_file, 4);
00968 }
00969
00970
00971
00972
00973
00974 find_spanning_tree (el);
00975
00976
00977
00978 for (i = 0; i < num_edges; i++)
00979 {
00980 edge e = INDEX_EDGE (el, i);
00981 struct edge_info *inf = EDGE_INFO (e);
00982 if ((e->flags & EDGE_FAKE) && !inf->ignore && !inf->on_tree)
00983 {
00984 inf->ignore = 1;
00985 ignored_edges++;
00986 }
00987 }
00988
00989 total_num_blocks += n_basic_blocks + 2;
00990 if (rtl_dump_file)
00991 fprintf (rtl_dump_file, "%d basic blocks\n", n_basic_blocks);
00992
00993 total_num_edges += num_edges;
00994 if (rtl_dump_file)
00995 fprintf (rtl_dump_file, "%d edges\n", num_edges);
00996
00997 total_num_edges_ignored += ignored_edges;
00998 if (rtl_dump_file)
00999 fprintf (rtl_dump_file, "%d ignored edges\n", ignored_edges);
01000
01001
01002
01003
01004
01005
01006 if (flag_test_coverage)
01007 {
01008 int flag_bits;
01009
01010 __write_gcov_string (name, strlen (name), bbg_file, -1);
01011
01012
01013 __write_long (profile_info.current_function_cfg_checksum, bbg_file, 4);
01014
01015
01016 __write_long (n_basic_blocks + 2, bbg_file, 4);
01017 __write_long (num_edges - ignored_edges + 1, bbg_file, 4);
01018
01019 FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb)
01020 {
01021 edge e;
01022 long count = 0;
01023
01024 for (e = bb->succ; e; e = e->succ_next)
01025 if (!EDGE_INFO (e)->ignore)
01026 count++;
01027 __write_long (count, bbg_file, 4);
01028
01029 for (e = bb->succ; e; e = e->succ_next)
01030 {
01031 struct edge_info *i = EDGE_INFO (e);
01032 if (!i->ignore)
01033 {
01034 flag_bits = 0;
01035 if (i->on_tree)
01036 flag_bits |= 0x1;
01037 if (e->flags & EDGE_FAKE)
01038 flag_bits |= 0x2;
01039 if (e->flags & EDGE_FALLTHRU)
01040 flag_bits |= 0x4;
01041
01042 __write_long (BB_TO_GCOV_INDEX (e->dest), bbg_file, 4);
01043 __write_long (flag_bits, bbg_file, 4);
01044 }
01045 }
01046 }
01047
01048
01049 __write_long (1, bbg_file, 4);
01050 __write_long (0, bbg_file, 4);
01051 __write_long (0x1, bbg_file, 4);
01052
01053
01054
01055 __write_long (-1, bbg_file, 4);
01056 }
01057
01058 if (flag_branch_probabilities)
01059 compute_branch_probabilities ();
01060
01061
01062
01063 if (profile_arc_flag)
01064 {
01065 instrument_edges (el);
01066 allocate_reg_info (max_reg_num (), FALSE, FALSE);
01067 }
01068
01069 remove_fake_edges ();
01070
01071
01072 cleanup_cfg (profile_arc_flag ? CLEANUP_EXPENSIVE : 0);
01073 if (rtl_dump_file)
01074 dump_flow_info (rtl_dump_file);
01075
01076 free_aux_for_edges ();
01077 free_edge_list (el);
01078 }
01079
01080
01081
01082
01083 static basic_block
01084 find_group (bb)
01085 basic_block bb;
01086 {
01087 basic_block group = bb, bb1;
01088
01089 while ((basic_block) group->aux != group)
01090 group = (basic_block) group->aux;
01091
01092
01093 while ((basic_block) bb->aux != group)
01094 {
01095 bb1 = (basic_block) bb->aux;
01096 bb->aux = (void *) group;
01097 bb = bb1;
01098 }
01099 return group;
01100 }
01101
01102 static void
01103 union_groups (bb1, bb2)
01104 basic_block bb1, bb2;
01105 {
01106 basic_block bb1g = find_group (bb1);
01107 basic_block bb2g = find_group (bb2);
01108
01109
01110
01111 if (bb1g == bb2g)
01112 abort ();
01113
01114 bb1g->aux = bb2g;
01115 }
01116
01117
01118
01119
01120
01121
01122
01123
01124 static void
01125 find_spanning_tree (el)
01126 struct edge_list *el;
01127 {
01128 int i;
01129 int num_edges = NUM_EDGES (el);
01130 basic_block bb;
01131
01132
01133 FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
01134 bb->aux = bb;
01135
01136
01137 union_groups (EXIT_BLOCK_PTR, ENTRY_BLOCK_PTR);
01138
01139
01140
01141
01142 for (i = 0; i < num_edges; i++)
01143 {
01144 edge e = INDEX_EDGE (el, i);
01145 if (((e->flags & (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL | EDGE_FAKE))
01146 || e->dest == EXIT_BLOCK_PTR
01147 )
01148 && !EDGE_INFO (e)->ignore
01149 && (find_group (e->src) != find_group (e->dest)))
01150 {
01151 if (rtl_dump_file)
01152 fprintf (rtl_dump_file, "Abnormal edge %d to %d put to tree\n",
01153 e->src->index, e->dest->index);
01154 EDGE_INFO (e)->on_tree = 1;
01155 union_groups (e->src, e->dest);
01156 }
01157 }
01158
01159
01160 for (i = 0; i < num_edges; i++)
01161 {
01162 edge e = INDEX_EDGE (el, i);
01163 if ((EDGE_CRITICAL_P (e))
01164 && !EDGE_INFO (e)->ignore
01165 && (find_group (e->src) != find_group (e->dest)))
01166 {
01167 if (rtl_dump_file)
01168 fprintf (rtl_dump_file, "Critical edge %d to %d put to tree\n",
01169 e->src->index, e->dest->index);
01170 EDGE_INFO (e)->on_tree = 1;
01171 union_groups (e->src, e->dest);
01172 }
01173 }
01174
01175
01176 for (i = 0; i < num_edges; i++)
01177 {
01178 edge e = INDEX_EDGE (el, i);
01179 if (find_group (e->src) != find_group (e->dest)
01180 && !EDGE_INFO (e)->ignore)
01181 {
01182 if (rtl_dump_file)
01183 fprintf (rtl_dump_file, "Normal edge %d to %d put to tree\n",
01184 e->src->index, e->dest->index);
01185 EDGE_INFO (e)->on_tree = 1;
01186 union_groups (e->src, e->dest);
01187 }
01188 }
01189
01190 FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
01191 bb->aux = NULL;
01192 }
01193
01194
01195
01196 void
01197 init_branch_prob (filename)
01198 const char *filename;
01199 {
01200 int len = strlen (filename);
01201 int i;
01202
01203 if (flag_test_coverage)
01204 {
01205 char *data_file, *bbg_file_name;
01206
01207
01208 data_file = (char *) alloca (len + 4);
01209 strcpy (data_file, filename);
01210 strcat (data_file, ".bb");
01211 if ((bb_file = fopen (data_file, "wb")) == 0)
01212 fatal_io_error ("can't open %s", data_file);
01213
01214
01215 bbg_file_name = (char *) alloca (len + 5);
01216 strcpy (bbg_file_name, filename);
01217 strcat (bbg_file_name, ".bbg");
01218 if ((bbg_file = fopen (bbg_file_name, "wb")) == 0)
01219 fatal_io_error ("can't open %s", bbg_file_name);
01220
01221
01222
01223 last_bb_file_name = 0;
01224 }
01225
01226 da_file_name = (char *) xmalloc (len + 4);
01227 strcpy (da_file_name, filename);
01228 strcat (da_file_name, ".da");
01229
01230 if (flag_branch_probabilities)
01231 {
01232 da_file = fopen (da_file_name, "rb");
01233 if (!da_file)
01234 warning ("file %s not found, execution counts assumed to be zero",
01235 da_file_name);
01236 }
01237
01238 if (profile_arc_flag)
01239 init_edge_profiler ();
01240
01241 total_num_blocks = 0;
01242 total_num_edges = 0;
01243 total_num_edges_ignored = 0;
01244 total_num_edges_instrumented = 0;
01245 total_num_blocks_created = 0;
01246 total_num_passes = 0;
01247 total_num_times_called = 0;
01248 total_num_branches = 0;
01249 total_num_never_executed = 0;
01250 for (i = 0; i < 20; i++)
01251 total_hist_br_prob[i] = 0;
01252 }
01253
01254
01255
01256
01257 void
01258 end_branch_prob ()
01259 {
01260 if (flag_test_coverage)
01261 {
01262 fclose (bb_file);
01263 fclose (bbg_file);
01264 unlink (da_file_name);
01265 }
01266
01267 if (flag_branch_probabilities && da_file)
01268 fclose (da_file);
01269
01270 if (rtl_dump_file)
01271 {
01272 fprintf (rtl_dump_file, "\n");
01273 fprintf (rtl_dump_file, "Total number of blocks: %d\n",
01274 total_num_blocks);
01275 fprintf (rtl_dump_file, "Total number of edges: %d\n", total_num_edges);
01276 fprintf (rtl_dump_file, "Total number of ignored edges: %d\n",
01277 total_num_edges_ignored);
01278 fprintf (rtl_dump_file, "Total number of instrumented edges: %d\n",
01279 total_num_edges_instrumented);
01280 fprintf (rtl_dump_file, "Total number of blocks created: %d\n",
01281 total_num_blocks_created);
01282 fprintf (rtl_dump_file, "Total number of graph solution passes: %d\n",
01283 total_num_passes);
01284 if (total_num_times_called != 0)
01285 fprintf (rtl_dump_file, "Average number of graph solution passes: %d\n",
01286 (total_num_passes + (total_num_times_called >> 1))
01287 / total_num_times_called);
01288 fprintf (rtl_dump_file, "Total number of branches: %d\n",
01289 total_num_branches);
01290 fprintf (rtl_dump_file, "Total number of branches never executed: %d\n",
01291 total_num_never_executed);
01292 if (total_num_branches)
01293 {
01294 int i;
01295
01296 for (i = 0; i < 10; i++)
01297 fprintf (rtl_dump_file, "%d%% branches in range %d-%d%%\n",
01298 (total_hist_br_prob[i] + total_hist_br_prob[19-i]) * 100
01299 / total_num_branches, 5*i, 5*i+5);
01300 }
01301 }
01302 }
01303
01304
01305
01306 static GTY(()) rtx profiler_label;
01307
01308
01309
01310 static void
01311 init_edge_profiler ()
01312 {
01313
01314 char buf[20];
01315 ASM_GENERATE_INTERNAL_LABEL (buf, "LPBX", 2);
01316 profiler_label = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
01317 }
01318
01319
01320
01321 static rtx
01322 gen_edge_profiler (edgeno)
01323 int edgeno;
01324 {
01325 enum machine_mode mode = mode_for_size (GCOV_TYPE_SIZE, MODE_INT, 0);
01326 rtx mem_ref, tmp;
01327 rtx sequence;
01328
01329 start_sequence ();
01330
01331 tmp = force_reg (Pmode, profiler_label);
01332 tmp = plus_constant (tmp, GCOV_TYPE_SIZE / BITS_PER_UNIT * edgeno);
01333 mem_ref = validize_mem (gen_rtx_MEM (mode, tmp));
01334
01335 set_mem_alias_set (mem_ref, new_alias_set ());
01336
01337 tmp = expand_simple_binop (mode, PLUS, mem_ref, const1_rtx,
01338 mem_ref, 0, OPTAB_WIDEN);
01339
01340 if (tmp != mem_ref)
01341 emit_move_insn (copy_rtx (mem_ref), tmp);
01342
01343 sequence = get_insns ();
01344 end_sequence ();
01345 return sequence;
01346 }
01347
01348
01349
01350
01351 void
01352 output_func_start_profiler ()
01353 {
01354 tree fnname, fndecl;
01355 char *name;
01356 char buf[20];
01357 const char *cfnname;
01358 rtx table_address;
01359 enum machine_mode mode = mode_for_size (GCOV_TYPE_SIZE, MODE_INT, 0);
01360 int save_flag_inline_functions = flag_inline_functions;
01361
01362
01363
01364 if (! need_func_profiler)
01365 return;
01366
01367 need_func_profiler = 0;
01368
01369
01370
01371
01372
01373
01374
01375
01376 fnname = get_file_function_name ('I');
01377 cfnname = IDENTIFIER_POINTER (fnname);
01378 name = concat (cfnname, "GCOV", NULL);
01379 fnname = get_identifier (name);
01380 free (name);
01381
01382 fndecl = build_decl (FUNCTION_DECL, fnname,
01383 build_function_type (void_type_node, NULL_TREE));
01384 DECL_EXTERNAL (fndecl) = 0;
01385
01386
01387
01388 TREE_PUBLIC (fndecl) = ! targetm.have_ctors_dtors;
01389
01390 TREE_USED (fndecl) = 1;
01391
01392 DECL_RESULT (fndecl) = build_decl (RESULT_DECL, NULL_TREE, void_type_node);
01393
01394 fndecl = (*lang_hooks.decls.pushdecl) (fndecl);
01395 rest_of_decl_compilation (fndecl, 0, 1, 0);
01396 announce_function (fndecl);
01397 current_function_decl = fndecl;
01398 DECL_INITIAL (fndecl) = error_mark_node;
01399 make_decl_rtl (fndecl, NULL);
01400 init_function_start (fndecl, input_filename, lineno);
01401 (*lang_hooks.decls.pushlevel) (0);
01402 expand_function_start (fndecl, 0);
01403 cfun->arc_profile = 0;
01404
01405
01406 ASM_GENERATE_INTERNAL_LABEL (buf, "LPBX", 0);
01407 table_address = force_reg (Pmode,
01408 gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf)));
01409 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__bb_init_func"), LCT_NORMAL,
01410 mode, 1, table_address, Pmode);
01411
01412 expand_function_end (input_filename, lineno, 0);
01413 (*lang_hooks.decls.poplevel) (1, 0, 1);
01414
01415
01416
01417
01418 flag_inline_functions = 0;
01419
01420 rest_of_compilation (fndecl);
01421
01422
01423 flag_inline_functions = save_flag_inline_functions;
01424
01425 if (! quiet_flag)
01426 fflush (asm_out_file);
01427 current_function_decl = NULL_TREE;
01428
01429 if (targetm.have_ctors_dtors)
01430 (* targetm.asm_out.constructor) (XEXP (DECL_RTL (fndecl), 0),
01431 DEFAULT_INIT_PRIORITY);
01432 }
01433
01434 #include "gt-profile.h"