Mercurial > hg > CbC > CbC_gcc
comparison gcc/profile.c @ 131:84e7813d76e9
gcc-8.2
author | mir3636 |
---|---|
date | Thu, 25 Oct 2018 07:37:49 +0900 |
parents | 04ced10e8804 |
children | 1830386684a0 |
comparison
equal
deleted
inserted
replaced
111:04ced10e8804 | 131:84e7813d76e9 |
---|---|
1 /* Calculate branch probabilities, and basic block execution counts. | 1 /* Calculate branch probabilities, and basic block execution counts. |
2 Copyright (C) 1990-2017 Free Software Foundation, Inc. | 2 Copyright (C) 1990-2018 Free Software Foundation, Inc. |
3 Contributed by James E. Wilson, UC Berkeley/Cygnus Support; | 3 Contributed by James E. Wilson, UC Berkeley/Cygnus Support; |
4 based on some ideas from Dain Samples of UC Berkeley. | 4 based on some ideas from Dain Samples of UC Berkeley. |
5 Further mangling by Bob Manson, Cygnus Support. | 5 Further mangling by Bob Manson, Cygnus Support. |
6 | 6 |
7 This file is part of GCC. | 7 This file is part of GCC. |
82 #define BB_INFO(b) ((struct bb_profile_info *) (b)->aux) | 82 #define BB_INFO(b) ((struct bb_profile_info *) (b)->aux) |
83 | 83 |
84 | 84 |
85 /* Counter summary from the last set of coverage counts read. */ | 85 /* Counter summary from the last set of coverage counts read. */ |
86 | 86 |
87 const struct gcov_ctr_summary *profile_info; | 87 gcov_summary *profile_info; |
88 | |
89 /* Counter working set information computed from the current counter | |
90 summary. Not initialized unless profile_info summary is non-NULL. */ | |
91 static gcov_working_set_t gcov_working_sets[NUM_GCOV_WORKING_SETS]; | |
92 | 88 |
93 /* Collect statistics on the performance of this pass for the entire source | 89 /* Collect statistics on the performance of this pass for the entire source |
94 file. */ | 90 file. */ |
95 | 91 |
96 static int total_num_blocks; | 92 static int total_num_blocks; |
101 static int total_num_passes; | 97 static int total_num_passes; |
102 static int total_num_times_called; | 98 static int total_num_times_called; |
103 static int total_hist_br_prob[20]; | 99 static int total_hist_br_prob[20]; |
104 static int total_num_branches; | 100 static int total_num_branches; |
105 | 101 |
106 /* Helper function to update gcov_working_sets. */ | |
107 | |
108 void add_working_set (gcov_working_set_t *set) { | |
109 int i = 0; | |
110 for (; i < NUM_GCOV_WORKING_SETS; i++) | |
111 gcov_working_sets[i] = set[i]; | |
112 } | |
113 | |
114 /* Forward declarations. */ | 102 /* Forward declarations. */ |
115 static void find_spanning_tree (struct edge_list *); | 103 static void find_spanning_tree (struct edge_list *); |
116 | 104 |
117 /* Add edge instrumentation code to the entire insn chain. | 105 /* Add edge instrumentation code to the entire insn chain. |
118 | 106 |
205 } | 193 } |
206 } | 194 } |
207 } | 195 } |
208 | 196 |
209 | 197 |
210 /* Fill the working set information into the profile_info structure. */ | |
211 | |
212 void | |
213 get_working_sets (void) | |
214 { | |
215 unsigned ws_ix, pctinc, pct; | |
216 gcov_working_set_t *ws_info; | |
217 | |
218 if (!profile_info) | |
219 return; | |
220 | |
221 compute_working_sets (profile_info, gcov_working_sets); | |
222 | |
223 if (dump_file) | |
224 { | |
225 fprintf (dump_file, "Counter working sets:\n"); | |
226 /* Multiply the percentage by 100 to avoid float. */ | |
227 pctinc = 100 * 100 / NUM_GCOV_WORKING_SETS; | |
228 for (ws_ix = 0, pct = pctinc; ws_ix < NUM_GCOV_WORKING_SETS; | |
229 ws_ix++, pct += pctinc) | |
230 { | |
231 if (ws_ix == NUM_GCOV_WORKING_SETS - 1) | |
232 pct = 9990; | |
233 ws_info = &gcov_working_sets[ws_ix]; | |
234 /* Print out the percentage using int arithmatic to avoid float. */ | |
235 fprintf (dump_file, "\t\t%u.%02u%%: num counts=%u, min counter=" | |
236 "%" PRId64 "\n", | |
237 pct / 100, pct - (pct / 100 * 100), | |
238 ws_info->num_counters, | |
239 (int64_t)ws_info->min_counter); | |
240 } | |
241 } | |
242 } | |
243 | |
244 /* Given a the desired percentage of the full profile (sum_all from the | |
245 summary), multiplied by 10 to avoid float in PCT_TIMES_10, returns | |
246 the corresponding working set information. If an exact match for | |
247 the percentage isn't found, the closest value is used. */ | |
248 | |
249 gcov_working_set_t * | |
250 find_working_set (unsigned pct_times_10) | |
251 { | |
252 unsigned i; | |
253 if (!profile_info) | |
254 return NULL; | |
255 gcc_assert (pct_times_10 <= 1000); | |
256 if (pct_times_10 >= 999) | |
257 return &gcov_working_sets[NUM_GCOV_WORKING_SETS - 1]; | |
258 i = pct_times_10 * NUM_GCOV_WORKING_SETS / 1000; | |
259 if (!i) | |
260 return &gcov_working_sets[0]; | |
261 return &gcov_working_sets[i - 1]; | |
262 } | |
263 | |
264 /* Computes hybrid profile for all matching entries in da_file. | 198 /* Computes hybrid profile for all matching entries in da_file. |
265 | 199 |
266 CFG_CHECKSUM is the precomputed checksum for the CFG. */ | 200 CFG_CHECKSUM is the precomputed checksum for the CFG. */ |
267 | 201 |
268 static gcov_type * | 202 static gcov_type * |
281 FOR_EACH_EDGE (e, ei, bb->succs) | 215 FOR_EACH_EDGE (e, ei, bb->succs) |
282 if (!EDGE_INFO (e)->ignore && !EDGE_INFO (e)->on_tree) | 216 if (!EDGE_INFO (e)->ignore && !EDGE_INFO (e)->on_tree) |
283 num_edges++; | 217 num_edges++; |
284 } | 218 } |
285 | 219 |
286 counts = get_coverage_counts (GCOV_COUNTER_ARCS, num_edges, cfg_checksum, | 220 counts = get_coverage_counts (GCOV_COUNTER_ARCS, cfg_checksum, |
287 lineno_checksum, &profile_info); | 221 lineno_checksum); |
288 if (!counts) | 222 if (!counts) |
289 return NULL; | 223 return NULL; |
290 | 224 |
291 get_working_sets (); | |
292 | |
293 if (dump_file && profile_info) | |
294 fprintf (dump_file, "Merged %u profiles with maximal count %u.\n", | |
295 profile_info->runs, (unsigned) profile_info->sum_max); | |
296 | |
297 return counts; | 225 return counts; |
298 } | 226 } |
299 | |
300 | 227 |
301 static bool | 228 static bool |
302 is_edge_inconsistent (vec<edge, va_gc> *edges) | 229 is_edge_inconsistent (vec<edge, va_gc> *edges) |
303 { | 230 { |
304 edge e; | 231 edge e; |
437 FOR_EACH_EDGE (e, ei, bb->succs) | 364 FOR_EACH_EDGE (e, ei, bb->succs) |
438 if (!EDGE_INFO (e)->ignore && !EDGE_INFO (e)->on_tree) | 365 if (!EDGE_INFO (e)->ignore && !EDGE_INFO (e)->on_tree) |
439 { | 366 { |
440 num_edges++; | 367 num_edges++; |
441 if (exec_counts) | 368 if (exec_counts) |
442 { | 369 edge_gcov_count (e) = exec_counts[exec_counts_pos++]; |
443 edge_gcov_count (e) = exec_counts[exec_counts_pos++]; | |
444 if (edge_gcov_count (e) > profile_info->sum_max) | |
445 { | |
446 if (flag_profile_correction) | |
447 { | |
448 static bool informed = 0; | |
449 if (dump_enabled_p () && !informed) | |
450 dump_printf_loc (MSG_NOTE, input_location, | |
451 "corrupted profile info: edge count" | |
452 " exceeds maximal count\n"); | |
453 informed = 1; | |
454 } | |
455 else | |
456 error ("corrupted profile info: edge from %i to %i exceeds maximal count", | |
457 bb->index, e->dest->index); | |
458 } | |
459 } | |
460 else | 370 else |
461 edge_gcov_count (e) = 0; | 371 edge_gcov_count (e) = 0; |
462 | 372 |
463 EDGE_INFO (e)->count_valid = 1; | 373 EDGE_INFO (e)->count_valid = 1; |
464 BB_INFO (bb)->succ_count--; | 374 BB_INFO (bb)->succ_count--; |
474 } | 384 } |
475 | 385 |
476 return num_edges; | 386 return num_edges; |
477 } | 387 } |
478 | 388 |
479 #define OVERLAP_BASE 10000 | |
480 | |
481 /* Compare the static estimated profile to the actual profile, and | |
482 return the "degree of overlap" measure between them. | |
483 | |
484 Degree of overlap is a number between 0 and OVERLAP_BASE. It is | |
485 the sum of each basic block's minimum relative weights between | |
486 two profiles. And overlap of OVERLAP_BASE means two profiles are | |
487 identical. */ | |
488 | |
489 static int | |
490 compute_frequency_overlap (void) | |
491 { | |
492 gcov_type count_total = 0, freq_total = 0; | |
493 int overlap = 0; | |
494 basic_block bb; | |
495 | |
496 FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun), NULL, next_bb) | |
497 { | |
498 count_total += bb_gcov_count (bb); | |
499 freq_total += bb->frequency; | |
500 } | |
501 | |
502 if (count_total == 0 || freq_total == 0) | |
503 return 0; | |
504 | |
505 FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun), NULL, next_bb) | |
506 overlap += MIN (bb_gcov_count (bb) * OVERLAP_BASE / count_total, | |
507 bb->frequency * OVERLAP_BASE / freq_total); | |
508 | |
509 return overlap; | |
510 } | |
511 | 389 |
512 /* Compute the branch probabilities for the various branches. | 390 /* Compute the branch probabilities for the various branches. |
513 Annotate them accordingly. | 391 Annotate them accordingly. |
514 | 392 |
515 CFG_CHECKSUM is the precomputed checksum for the CFG. */ | 393 CFG_CHECKSUM is the precomputed checksum for the CFG. */ |
527 gcov_type *exec_counts = get_exec_counts (cfg_checksum, lineno_checksum); | 405 gcov_type *exec_counts = get_exec_counts (cfg_checksum, lineno_checksum); |
528 int inconsistent = 0; | 406 int inconsistent = 0; |
529 | 407 |
530 /* Very simple sanity checks so we catch bugs in our profiling code. */ | 408 /* Very simple sanity checks so we catch bugs in our profiling code. */ |
531 if (!profile_info) | 409 if (!profile_info) |
532 return; | 410 { |
411 if (dump_file) | |
412 fprintf (dump_file, "Profile info is missing; giving up\n"); | |
413 return; | |
414 } | |
533 | 415 |
534 bb_gcov_counts.safe_grow_cleared (last_basic_block_for_fn (cfun)); | 416 bb_gcov_counts.safe_grow_cleared (last_basic_block_for_fn (cfun)); |
535 edge_gcov_counts = new hash_map<edge,gcov_type>; | 417 edge_gcov_counts = new hash_map<edge,gcov_type>; |
536 | |
537 if (profile_info->sum_all < profile_info->sum_max) | |
538 { | |
539 error ("corrupted profile info: sum_all is smaller than sum_max"); | |
540 exec_counts = NULL; | |
541 } | |
542 | 418 |
543 /* Attach extra info block to each bb. */ | 419 /* Attach extra info block to each bb. */ |
544 alloc_aux_for_blocks (sizeof (struct bb_profile_info)); | 420 alloc_aux_for_blocks (sizeof (struct bb_profile_info)); |
545 FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun), NULL, next_bb) | 421 FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun), NULL, next_bb) |
546 { | 422 { |
674 changes = 1; | 550 changes = 1; |
675 } | 551 } |
676 } | 552 } |
677 } | 553 } |
678 } | 554 } |
679 if (dump_file) | |
680 { | |
681 int overlap = compute_frequency_overlap (); | |
682 gimple_dump_cfg (dump_file, dump_flags); | |
683 fprintf (dump_file, "Static profile overlap: %d.%d%%\n", | |
684 overlap / (OVERLAP_BASE / 100), | |
685 overlap % (OVERLAP_BASE / 100)); | |
686 } | |
687 | 555 |
688 total_num_passes += passes; | 556 total_num_passes += passes; |
689 if (dump_file) | 557 if (dump_file) |
690 fprintf (dump_file, "Graph solving took %d passes.\n\n", passes); | 558 fprintf (dump_file, "Graph solving took %d passes.\n\n", passes); |
691 | 559 |
706 /* Inconsistency detected. Make it flow-consistent. */ | 574 /* Inconsistency detected. Make it flow-consistent. */ |
707 static int informed = 0; | 575 static int informed = 0; |
708 if (dump_enabled_p () && informed == 0) | 576 if (dump_enabled_p () && informed == 0) |
709 { | 577 { |
710 informed = 1; | 578 informed = 1; |
711 dump_printf_loc (MSG_NOTE, input_location, | 579 dump_printf_loc (MSG_NOTE, |
580 dump_location_t::from_location_t (input_location), | |
712 "correcting inconsistent profile data\n"); | 581 "correcting inconsistent profile data\n"); |
713 } | 582 } |
714 correct_negative_edge_counts (); | 583 correct_negative_edge_counts (); |
715 /* Set bb counts to the sum of the outgoing edge counts */ | 584 /* Set bb counts to the sum of the outgoing edge counts */ |
716 set_bb_counts (); | 585 set_bb_counts (); |
827 && EDGE_COUNT (bb->succs) >= 2) | 696 && EDGE_COUNT (bb->succs) >= 2) |
828 num_branches++; | 697 num_branches++; |
829 } | 698 } |
830 } | 699 } |
831 | 700 |
832 FOR_ALL_BB_FN (bb, cfun) | 701 /* If we have real data, use them! */ |
833 { | 702 if (bb_gcov_count (ENTRY_BLOCK_PTR_FOR_FN (cfun)) |
703 || !flag_guess_branch_prob) | |
704 FOR_ALL_BB_FN (bb, cfun) | |
834 bb->count = profile_count::from_gcov_type (bb_gcov_count (bb)); | 705 bb->count = profile_count::from_gcov_type (bb_gcov_count (bb)); |
835 } | 706 /* If function was not trained, preserve local estimates including statically |
707 determined zero counts. */ | |
708 else | |
709 FOR_ALL_BB_FN (bb, cfun) | |
710 if (!(bb->count == profile_count::zero ())) | |
711 bb->count = bb->count.global0 (); | |
712 | |
836 bb_gcov_counts.release (); | 713 bb_gcov_counts.release (); |
837 delete edge_gcov_counts; | 714 delete edge_gcov_counts; |
838 edge_gcov_counts = NULL; | 715 edge_gcov_counts = NULL; |
839 | 716 |
840 counts_to_freqs (); | 717 update_max_bb_count (); |
841 | 718 |
842 if (dump_file) | 719 if (dump_file) |
843 { | 720 { |
844 fprintf (dump_file, "%d branches\n", num_branches); | 721 fprintf (dump_file, "%d branches\n", num_branches); |
845 if (num_branches) | 722 if (num_branches) |
891 { | 768 { |
892 histogram_counts[t] = NULL; | 769 histogram_counts[t] = NULL; |
893 continue; | 770 continue; |
894 } | 771 } |
895 | 772 |
896 histogram_counts[t] = | 773 histogram_counts[t] = get_coverage_counts (COUNTER_FOR_HIST_TYPE (t), |
897 get_coverage_counts (COUNTER_FOR_HIST_TYPE (t), | 774 cfg_checksum, |
898 n_histogram_counters[t], cfg_checksum, | 775 lineno_checksum); |
899 lineno_checksum, NULL); | |
900 if (histogram_counts[t]) | 776 if (histogram_counts[t]) |
901 any = 1; | 777 any = 1; |
902 act_count[t] = histogram_counts[t]; | 778 act_count[t] = histogram_counts[t]; |
903 } | 779 } |
904 if (!any) | 780 if (!any) |
939 | 815 |
940 for (t = 0; t < GCOV_N_VALUE_COUNTERS; t++) | 816 for (t = 0; t < GCOV_N_VALUE_COUNTERS; t++) |
941 free (histogram_counts[t]); | 817 free (histogram_counts[t]); |
942 } | 818 } |
943 | 819 |
820 /* Location triplet which records a location. */ | |
821 struct location_triplet | |
822 { | |
823 const char *filename; | |
824 int lineno; | |
825 int bb_index; | |
826 }; | |
827 | |
828 /* Traits class for streamed_locations hash set below. */ | |
829 | |
830 struct location_triplet_hash : typed_noop_remove <location_triplet> | |
831 { | |
832 typedef location_triplet value_type; | |
833 typedef location_triplet compare_type; | |
834 | |
835 static hashval_t | |
836 hash (const location_triplet &ref) | |
837 { | |
838 inchash::hash hstate (0); | |
839 if (ref.filename) | |
840 hstate.add_int (strlen (ref.filename)); | |
841 hstate.add_int (ref.lineno); | |
842 hstate.add_int (ref.bb_index); | |
843 return hstate.end (); | |
844 } | |
845 | |
846 static bool | |
847 equal (const location_triplet &ref1, const location_triplet &ref2) | |
848 { | |
849 return ref1.lineno == ref2.lineno | |
850 && ref1.bb_index == ref2.bb_index | |
851 && ref1.filename != NULL | |
852 && ref2.filename != NULL | |
853 && strcmp (ref1.filename, ref2.filename) == 0; | |
854 } | |
855 | |
856 static void | |
857 mark_deleted (location_triplet &ref) | |
858 { | |
859 ref.lineno = -1; | |
860 } | |
861 | |
862 static void | |
863 mark_empty (location_triplet &ref) | |
864 { | |
865 ref.lineno = -2; | |
866 } | |
867 | |
868 static bool | |
869 is_deleted (const location_triplet &ref) | |
870 { | |
871 return ref.lineno == -1; | |
872 } | |
873 | |
874 static bool | |
875 is_empty (const location_triplet &ref) | |
876 { | |
877 return ref.lineno == -2; | |
878 } | |
879 }; | |
880 | |
881 | |
882 | |
883 | |
944 /* When passed NULL as file_name, initialize. | 884 /* When passed NULL as file_name, initialize. |
945 When passed something else, output the necessary commands to change | 885 When passed something else, output the necessary commands to change |
946 line to LINE and offset to FILE_NAME. */ | 886 line to LINE and offset to FILE_NAME. */ |
947 static void | 887 static void |
948 output_location (char const *file_name, int line, | 888 output_location (hash_set<location_triplet_hash> *streamed_locations, |
889 char const *file_name, int line, | |
949 gcov_position_t *offset, basic_block bb) | 890 gcov_position_t *offset, basic_block bb) |
950 { | 891 { |
951 static char const *prev_file_name; | 892 static char const *prev_file_name; |
952 static int prev_line; | 893 static int prev_line; |
953 bool name_differs, line_differs; | 894 bool name_differs, line_differs; |
895 | |
896 location_triplet triplet; | |
897 triplet.filename = file_name; | |
898 triplet.lineno = line; | |
899 triplet.bb_index = bb ? bb->index : 0; | |
900 | |
901 if (streamed_locations->add (triplet)) | |
902 return; | |
954 | 903 |
955 if (!file_name) | 904 if (!file_name) |
956 { | 905 { |
957 prev_file_name = NULL; | 906 prev_file_name = NULL; |
958 prev_line = -1; | 907 prev_line = -1; |
1037 | 986 |
1038 total_num_times_called++; | 987 total_num_times_called++; |
1039 | 988 |
1040 flow_call_edges_add (NULL); | 989 flow_call_edges_add (NULL); |
1041 add_noreturn_fake_exit_edges (); | 990 add_noreturn_fake_exit_edges (); |
991 | |
992 hash_set <location_triplet_hash> streamed_locations; | |
1042 | 993 |
1043 /* We can't handle cyclic regions constructed using abnormal edges. | 994 /* We can't handle cyclic regions constructed using abnormal edges. |
1044 To avoid these we replace every source of abnormal edge by a fake | 995 To avoid these we replace every source of abnormal edge by a fake |
1045 edge from entry node and every destination by fake edge to exit. | 996 edge from entry node and every destination by fake edge to exit. |
1046 This keeps graph acyclic and our calculation exact for all normal | 997 This keeps graph acyclic and our calculation exact for all normal |
1274 gcov_write_length (offset); | 1225 gcov_write_length (offset); |
1275 } | 1226 } |
1276 | 1227 |
1277 /* Line numbers. */ | 1228 /* Line numbers. */ |
1278 /* Initialize the output. */ | 1229 /* Initialize the output. */ |
1279 output_location (NULL, 0, NULL, NULL); | 1230 output_location (&streamed_locations, NULL, 0, NULL, NULL); |
1231 | |
1232 hash_set<int_hash <location_t, 0, 2> > seen_locations; | |
1280 | 1233 |
1281 FOR_EACH_BB_FN (bb, cfun) | 1234 FOR_EACH_BB_FN (bb, cfun) |
1282 { | 1235 { |
1283 gimple_stmt_iterator gsi; | 1236 gimple_stmt_iterator gsi; |
1284 gcov_position_t offset = 0; | 1237 gcov_position_t offset = 0; |
1285 | 1238 |
1286 if (bb == ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb) | 1239 if (bb == ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb) |
1287 { | 1240 { |
1288 expanded_location curr_location = | 1241 location_t loc = DECL_SOURCE_LOCATION (current_function_decl); |
1289 expand_location (DECL_SOURCE_LOCATION (current_function_decl)); | 1242 seen_locations.add (loc); |
1290 output_location (curr_location.file, curr_location.line, | 1243 expanded_location curr_location = expand_location (loc); |
1291 &offset, bb); | 1244 output_location (&streamed_locations, curr_location.file, |
1245 curr_location.line, &offset, bb); | |
1292 } | 1246 } |
1293 | 1247 |
1294 for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) | 1248 for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) |
1295 { | 1249 { |
1296 gimple *stmt = gsi_stmt (gsi); | 1250 gimple *stmt = gsi_stmt (gsi); |
1297 if (!RESERVED_LOCATION_P (gimple_location (stmt))) | 1251 location_t loc = gimple_location (stmt); |
1298 output_location (gimple_filename (stmt), gimple_lineno (stmt), | 1252 if (!RESERVED_LOCATION_P (loc)) |
1299 &offset, bb); | 1253 { |
1300 } | 1254 seen_locations.add (loc); |
1301 | 1255 output_location (&streamed_locations, gimple_filename (stmt), |
1302 /* Notice GOTO expressions eliminated while constructing the CFG. */ | 1256 gimple_lineno (stmt), &offset, bb); |
1257 } | |
1258 } | |
1259 | |
1260 /* Notice GOTO expressions eliminated while constructing the CFG. | |
1261 It's hard to distinguish such expression, but goto_locus should | |
1262 not be any of already seen location. */ | |
1263 location_t loc; | |
1303 if (single_succ_p (bb) | 1264 if (single_succ_p (bb) |
1304 && !RESERVED_LOCATION_P (single_succ_edge (bb)->goto_locus)) | 1265 && (loc = single_succ_edge (bb)->goto_locus) |
1305 { | 1266 && !RESERVED_LOCATION_P (loc) |
1306 expanded_location curr_location | 1267 && !seen_locations.contains (loc)) |
1307 = expand_location (single_succ_edge (bb)->goto_locus); | 1268 { |
1308 output_location (curr_location.file, curr_location.line, | 1269 expanded_location curr_location = expand_location (loc); |
1309 &offset, bb); | 1270 output_location (&streamed_locations, curr_location.file, |
1271 curr_location.line, &offset, bb); | |
1310 } | 1272 } |
1311 | 1273 |
1312 if (offset) | 1274 if (offset) |
1313 { | 1275 { |
1314 /* A file of NULL indicates the end of run. */ | 1276 /* A file of NULL indicates the end of run. */ |