11debfc3dSmrg /* Calculate branch probabilities, and basic block execution counts.
2*8feb0f0bSmrg Copyright (C) 1990-2020 Free Software Foundation, Inc.
31debfc3dSmrg Contributed by James E. Wilson, UC Berkeley/Cygnus Support;
41debfc3dSmrg based on some ideas from Dain Samples of UC Berkeley.
51debfc3dSmrg Further mangling by Bob Manson, Cygnus Support.
61debfc3dSmrg
71debfc3dSmrg This file is part of GCC.
81debfc3dSmrg
91debfc3dSmrg GCC is free software; you can redistribute it and/or modify it under
101debfc3dSmrg the terms of the GNU General Public License as published by the Free
111debfc3dSmrg Software Foundation; either version 3, or (at your option) any later
121debfc3dSmrg version.
131debfc3dSmrg
141debfc3dSmrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
151debfc3dSmrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
161debfc3dSmrg FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
171debfc3dSmrg for more details.
181debfc3dSmrg
191debfc3dSmrg You should have received a copy of the GNU General Public License
201debfc3dSmrg along with GCC; see the file COPYING3. If not see
211debfc3dSmrg <http://www.gnu.org/licenses/>. */
221debfc3dSmrg
231debfc3dSmrg /* Generate basic block profile instrumentation and auxiliary files.
241debfc3dSmrg Profile generation is optimized, so that not all arcs in the basic
251debfc3dSmrg block graph need instrumenting. First, the BB graph is closed with
261debfc3dSmrg one entry (function start), and one exit (function exit). Any
271debfc3dSmrg ABNORMAL_EDGE cannot be instrumented (because there is no control
281debfc3dSmrg path to place the code). We close the graph by inserting fake
291debfc3dSmrg EDGE_FAKE edges to the EXIT_BLOCK, from the sources of abnormal
301debfc3dSmrg edges that do not go to the exit_block. We ignore such abnormal
311debfc3dSmrg edges. Naturally these fake edges are never directly traversed,
321debfc3dSmrg and so *cannot* be directly instrumented. Some other graph
331debfc3dSmrg massaging is done. To optimize the instrumentation we generate the
341debfc3dSmrg BB minimal span tree, only edges that are not on the span tree
351debfc3dSmrg (plus the entry point) need instrumenting. From that information
361debfc3dSmrg all other edge counts can be deduced. By construction all fake
371debfc3dSmrg edges must be on the spanning tree. We also attempt to place
381debfc3dSmrg EDGE_CRITICAL edges on the spanning tree.
391debfc3dSmrg
401debfc3dSmrg The auxiliary files generated are <dumpbase>.gcno (at compile time)
411debfc3dSmrg and <dumpbase>.gcda (at run time). The format is
421debfc3dSmrg described in full in gcov-io.h. */
431debfc3dSmrg
441debfc3dSmrg /* ??? Register allocation should use basic block execution counts to
451debfc3dSmrg give preference to the most commonly executed blocks. */
461debfc3dSmrg
471debfc3dSmrg /* ??? Should calculate branch probabilities before instrumenting code, since
481debfc3dSmrg then we can use arc counts to help decide which arcs to instrument. */
491debfc3dSmrg
501debfc3dSmrg #include "config.h"
511debfc3dSmrg #include "system.h"
521debfc3dSmrg #include "coretypes.h"
531debfc3dSmrg #include "backend.h"
541debfc3dSmrg #include "rtl.h"
551debfc3dSmrg #include "tree.h"
561debfc3dSmrg #include "gimple.h"
571debfc3dSmrg #include "cfghooks.h"
581debfc3dSmrg #include "cgraph.h"
591debfc3dSmrg #include "coverage.h"
601debfc3dSmrg #include "diagnostic-core.h"
611debfc3dSmrg #include "cfganal.h"
621debfc3dSmrg #include "value-prof.h"
631debfc3dSmrg #include "gimple-iterator.h"
641debfc3dSmrg #include "tree-cfg.h"
651debfc3dSmrg #include "dumpfile.h"
661debfc3dSmrg #include "cfgloop.h"
671debfc3dSmrg
681debfc3dSmrg #include "profile.h"
691debfc3dSmrg
70a2dc1f3fSmrg /* Map from BBs/edges to gcov counters. */
71a2dc1f3fSmrg vec<gcov_type> bb_gcov_counts;
72a2dc1f3fSmrg hash_map<edge,gcov_type> *edge_gcov_counts;
73a2dc1f3fSmrg
741debfc3dSmrg struct bb_profile_info {
751debfc3dSmrg unsigned int count_valid : 1;
761debfc3dSmrg
771debfc3dSmrg /* Number of successor and predecessor edges. */
781debfc3dSmrg gcov_type succ_count;
791debfc3dSmrg gcov_type pred_count;
801debfc3dSmrg };
811debfc3dSmrg
821debfc3dSmrg #define BB_INFO(b) ((struct bb_profile_info *) (b)->aux)
831debfc3dSmrg
841debfc3dSmrg
851debfc3dSmrg /* Counter summary from the last set of coverage counts read. */
861debfc3dSmrg
87c0a68be4Smrg gcov_summary *profile_info;
881debfc3dSmrg
891debfc3dSmrg /* Collect statistics on the performance of this pass for the entire source
901debfc3dSmrg file. */
911debfc3dSmrg
921debfc3dSmrg static int total_num_blocks;
931debfc3dSmrg static int total_num_edges;
941debfc3dSmrg static int total_num_edges_ignored;
951debfc3dSmrg static int total_num_edges_instrumented;
961debfc3dSmrg static int total_num_blocks_created;
971debfc3dSmrg static int total_num_passes;
981debfc3dSmrg static int total_num_times_called;
991debfc3dSmrg static int total_hist_br_prob[20];
1001debfc3dSmrg static int total_num_branches;
1011debfc3dSmrg
1021debfc3dSmrg /* Forward declarations. */
1031debfc3dSmrg static void find_spanning_tree (struct edge_list *);
1041debfc3dSmrg
1051debfc3dSmrg /* Add edge instrumentation code to the entire insn chain.
1061debfc3dSmrg
1071debfc3dSmrg F is the first insn of the chain.
1081debfc3dSmrg NUM_BLOCKS is the number of basic blocks found in F. */
1091debfc3dSmrg
1101debfc3dSmrg static unsigned
instrument_edges(struct edge_list * el)1111debfc3dSmrg instrument_edges (struct edge_list *el)
1121debfc3dSmrg {
1131debfc3dSmrg unsigned num_instr_edges = 0;
1141debfc3dSmrg int num_edges = NUM_EDGES (el);
1151debfc3dSmrg basic_block bb;
1161debfc3dSmrg
1171debfc3dSmrg FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun), NULL, next_bb)
1181debfc3dSmrg {
1191debfc3dSmrg edge e;
1201debfc3dSmrg edge_iterator ei;
1211debfc3dSmrg
1221debfc3dSmrg FOR_EACH_EDGE (e, ei, bb->succs)
1231debfc3dSmrg {
1241debfc3dSmrg struct edge_profile_info *inf = EDGE_INFO (e);
1251debfc3dSmrg
1261debfc3dSmrg if (!inf->ignore && !inf->on_tree)
1271debfc3dSmrg {
1281debfc3dSmrg gcc_assert (!(e->flags & EDGE_ABNORMAL));
1291debfc3dSmrg if (dump_file)
1301debfc3dSmrg fprintf (dump_file, "Edge %d to %d instrumented%s\n",
1311debfc3dSmrg e->src->index, e->dest->index,
1321debfc3dSmrg EDGE_CRITICAL_P (e) ? " (and split)" : "");
1331debfc3dSmrg gimple_gen_edge_profiler (num_instr_edges++, e);
1341debfc3dSmrg }
1351debfc3dSmrg }
1361debfc3dSmrg }
1371debfc3dSmrg
1381debfc3dSmrg total_num_blocks_created += num_edges;
1391debfc3dSmrg if (dump_file)
1401debfc3dSmrg fprintf (dump_file, "%d edges instrumented\n", num_instr_edges);
1411debfc3dSmrg return num_instr_edges;
1421debfc3dSmrg }
1431debfc3dSmrg
1441debfc3dSmrg /* Add code to measure histograms for values in list VALUES. */
1451debfc3dSmrg static void
instrument_values(histogram_values values)1461debfc3dSmrg instrument_values (histogram_values values)
1471debfc3dSmrg {
1481debfc3dSmrg unsigned i;
1491debfc3dSmrg
1501debfc3dSmrg /* Emit code to generate the histograms before the insns. */
1511debfc3dSmrg
1521debfc3dSmrg for (i = 0; i < values.length (); i++)
1531debfc3dSmrg {
1541debfc3dSmrg histogram_value hist = values[i];
1551debfc3dSmrg unsigned t = COUNTER_FOR_HIST_TYPE (hist->type);
1561debfc3dSmrg
1571debfc3dSmrg if (!coverage_counter_alloc (t, hist->n_counters))
1581debfc3dSmrg continue;
1591debfc3dSmrg
1601debfc3dSmrg switch (hist->type)
1611debfc3dSmrg {
1621debfc3dSmrg case HIST_TYPE_INTERVAL:
163*8feb0f0bSmrg gimple_gen_interval_profiler (hist, t);
1641debfc3dSmrg break;
1651debfc3dSmrg
1661debfc3dSmrg case HIST_TYPE_POW2:
167*8feb0f0bSmrg gimple_gen_pow2_profiler (hist, t);
1681debfc3dSmrg break;
1691debfc3dSmrg
170*8feb0f0bSmrg case HIST_TYPE_TOPN_VALUES:
171*8feb0f0bSmrg gimple_gen_topn_values_profiler (hist, t);
1721debfc3dSmrg break;
1731debfc3dSmrg
1741debfc3dSmrg case HIST_TYPE_INDIR_CALL:
175*8feb0f0bSmrg gimple_gen_ic_profiler (hist, t);
1761debfc3dSmrg break;
1771debfc3dSmrg
1781debfc3dSmrg case HIST_TYPE_AVERAGE:
179*8feb0f0bSmrg gimple_gen_average_profiler (hist, t);
1801debfc3dSmrg break;
1811debfc3dSmrg
1821debfc3dSmrg case HIST_TYPE_IOR:
183*8feb0f0bSmrg gimple_gen_ior_profiler (hist, t);
1841debfc3dSmrg break;
1851debfc3dSmrg
1861debfc3dSmrg case HIST_TYPE_TIME_PROFILE:
187*8feb0f0bSmrg gimple_gen_time_profiler (t);
1881debfc3dSmrg break;
1891debfc3dSmrg
1901debfc3dSmrg default:
1911debfc3dSmrg gcc_unreachable ();
1921debfc3dSmrg }
1931debfc3dSmrg }
1941debfc3dSmrg }
1951debfc3dSmrg
1961debfc3dSmrg
1971debfc3dSmrg /* Computes hybrid profile for all matching entries in da_file.
1981debfc3dSmrg
1991debfc3dSmrg CFG_CHECKSUM is the precomputed checksum for the CFG. */
2001debfc3dSmrg
2011debfc3dSmrg static gcov_type *
get_exec_counts(unsigned cfg_checksum,unsigned lineno_checksum)2021debfc3dSmrg get_exec_counts (unsigned cfg_checksum, unsigned lineno_checksum)
2031debfc3dSmrg {
2041debfc3dSmrg unsigned num_edges = 0;
2051debfc3dSmrg basic_block bb;
2061debfc3dSmrg gcov_type *counts;
2071debfc3dSmrg
2081debfc3dSmrg /* Count the edges to be (possibly) instrumented. */
2091debfc3dSmrg FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun), NULL, next_bb)
2101debfc3dSmrg {
2111debfc3dSmrg edge e;
2121debfc3dSmrg edge_iterator ei;
2131debfc3dSmrg
2141debfc3dSmrg FOR_EACH_EDGE (e, ei, bb->succs)
2151debfc3dSmrg if (!EDGE_INFO (e)->ignore && !EDGE_INFO (e)->on_tree)
2161debfc3dSmrg num_edges++;
2171debfc3dSmrg }
2181debfc3dSmrg
219c0a68be4Smrg counts = get_coverage_counts (GCOV_COUNTER_ARCS, cfg_checksum,
220c0a68be4Smrg lineno_checksum, num_edges);
2211debfc3dSmrg if (!counts)
2221debfc3dSmrg return NULL;
2231debfc3dSmrg
2241debfc3dSmrg return counts;
2251debfc3dSmrg }
2261debfc3dSmrg
2271debfc3dSmrg static bool
is_edge_inconsistent(vec<edge,va_gc> * edges)2281debfc3dSmrg is_edge_inconsistent (vec<edge, va_gc> *edges)
2291debfc3dSmrg {
2301debfc3dSmrg edge e;
2311debfc3dSmrg edge_iterator ei;
2321debfc3dSmrg FOR_EACH_EDGE (e, ei, edges)
2331debfc3dSmrg {
2341debfc3dSmrg if (!EDGE_INFO (e)->ignore)
2351debfc3dSmrg {
236a2dc1f3fSmrg if (edge_gcov_count (e) < 0
2371debfc3dSmrg && (!(e->flags & EDGE_FAKE)
2381debfc3dSmrg || !block_ends_with_call_p (e->src)))
2391debfc3dSmrg {
2401debfc3dSmrg if (dump_file)
2411debfc3dSmrg {
2421debfc3dSmrg fprintf (dump_file,
2431debfc3dSmrg "Edge %i->%i is inconsistent, count%" PRId64,
244a2dc1f3fSmrg e->src->index, e->dest->index, edge_gcov_count (e));
2451debfc3dSmrg dump_bb (dump_file, e->src, 0, TDF_DETAILS);
2461debfc3dSmrg dump_bb (dump_file, e->dest, 0, TDF_DETAILS);
2471debfc3dSmrg }
2481debfc3dSmrg return true;
2491debfc3dSmrg }
2501debfc3dSmrg }
2511debfc3dSmrg }
2521debfc3dSmrg return false;
2531debfc3dSmrg }
2541debfc3dSmrg
2551debfc3dSmrg static void
correct_negative_edge_counts(void)2561debfc3dSmrg correct_negative_edge_counts (void)
2571debfc3dSmrg {
2581debfc3dSmrg basic_block bb;
2591debfc3dSmrg edge e;
2601debfc3dSmrg edge_iterator ei;
2611debfc3dSmrg
2621debfc3dSmrg FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun), NULL, next_bb)
2631debfc3dSmrg {
2641debfc3dSmrg FOR_EACH_EDGE (e, ei, bb->succs)
2651debfc3dSmrg {
266a2dc1f3fSmrg if (edge_gcov_count (e) < 0)
267a2dc1f3fSmrg edge_gcov_count (e) = 0;
2681debfc3dSmrg }
2691debfc3dSmrg }
2701debfc3dSmrg }
2711debfc3dSmrg
2721debfc3dSmrg /* Check consistency.
2731debfc3dSmrg Return true if inconsistency is found. */
2741debfc3dSmrg static bool
is_inconsistent(void)2751debfc3dSmrg is_inconsistent (void)
2761debfc3dSmrg {
2771debfc3dSmrg basic_block bb;
2781debfc3dSmrg bool inconsistent = false;
2791debfc3dSmrg FOR_EACH_BB_FN (bb, cfun)
2801debfc3dSmrg {
2811debfc3dSmrg inconsistent |= is_edge_inconsistent (bb->preds);
2821debfc3dSmrg if (!dump_file && inconsistent)
2831debfc3dSmrg return true;
2841debfc3dSmrg inconsistent |= is_edge_inconsistent (bb->succs);
2851debfc3dSmrg if (!dump_file && inconsistent)
2861debfc3dSmrg return true;
287a2dc1f3fSmrg if (bb_gcov_count (bb) < 0)
2881debfc3dSmrg {
2891debfc3dSmrg if (dump_file)
2901debfc3dSmrg {
2911debfc3dSmrg fprintf (dump_file, "BB %i count is negative "
2921debfc3dSmrg "%" PRId64,
2931debfc3dSmrg bb->index,
294a2dc1f3fSmrg bb_gcov_count (bb));
2951debfc3dSmrg dump_bb (dump_file, bb, 0, TDF_DETAILS);
2961debfc3dSmrg }
2971debfc3dSmrg inconsistent = true;
2981debfc3dSmrg }
299a2dc1f3fSmrg if (bb_gcov_count (bb) != sum_edge_counts (bb->preds))
3001debfc3dSmrg {
3011debfc3dSmrg if (dump_file)
3021debfc3dSmrg {
3031debfc3dSmrg fprintf (dump_file, "BB %i count does not match sum of incoming edges "
3041debfc3dSmrg "%" PRId64" should be %" PRId64,
3051debfc3dSmrg bb->index,
306a2dc1f3fSmrg bb_gcov_count (bb),
3071debfc3dSmrg sum_edge_counts (bb->preds));
3081debfc3dSmrg dump_bb (dump_file, bb, 0, TDF_DETAILS);
3091debfc3dSmrg }
3101debfc3dSmrg inconsistent = true;
3111debfc3dSmrg }
312a2dc1f3fSmrg if (bb_gcov_count (bb) != sum_edge_counts (bb->succs) &&
3131debfc3dSmrg ! (find_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun)) != NULL
3141debfc3dSmrg && block_ends_with_call_p (bb)))
3151debfc3dSmrg {
3161debfc3dSmrg if (dump_file)
3171debfc3dSmrg {
3181debfc3dSmrg fprintf (dump_file, "BB %i count does not match sum of outgoing edges "
3191debfc3dSmrg "%" PRId64" should be %" PRId64,
3201debfc3dSmrg bb->index,
321a2dc1f3fSmrg bb_gcov_count (bb),
3221debfc3dSmrg sum_edge_counts (bb->succs));
3231debfc3dSmrg dump_bb (dump_file, bb, 0, TDF_DETAILS);
3241debfc3dSmrg }
3251debfc3dSmrg inconsistent = true;
3261debfc3dSmrg }
3271debfc3dSmrg if (!dump_file && inconsistent)
3281debfc3dSmrg return true;
3291debfc3dSmrg }
3301debfc3dSmrg
3311debfc3dSmrg return inconsistent;
3321debfc3dSmrg }
3331debfc3dSmrg
3341debfc3dSmrg /* Set each basic block count to the sum of its outgoing edge counts */
3351debfc3dSmrg static void
set_bb_counts(void)3361debfc3dSmrg set_bb_counts (void)
3371debfc3dSmrg {
3381debfc3dSmrg basic_block bb;
3391debfc3dSmrg FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun), NULL, next_bb)
3401debfc3dSmrg {
341a2dc1f3fSmrg bb_gcov_count (bb) = sum_edge_counts (bb->succs);
342a2dc1f3fSmrg gcc_assert (bb_gcov_count (bb) >= 0);
3431debfc3dSmrg }
3441debfc3dSmrg }
3451debfc3dSmrg
3461debfc3dSmrg /* Reads profile data and returns total number of edge counts read */
3471debfc3dSmrg static int
read_profile_edge_counts(gcov_type * exec_counts)3481debfc3dSmrg read_profile_edge_counts (gcov_type *exec_counts)
3491debfc3dSmrg {
3501debfc3dSmrg basic_block bb;
3511debfc3dSmrg int num_edges = 0;
3521debfc3dSmrg int exec_counts_pos = 0;
3531debfc3dSmrg /* For each edge not on the spanning tree, set its execution count from
3541debfc3dSmrg the .da file. */
3551debfc3dSmrg /* The first count in the .da file is the number of times that the function
3561debfc3dSmrg was entered. This is the exec_count for block zero. */
3571debfc3dSmrg
3581debfc3dSmrg FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun), NULL, next_bb)
3591debfc3dSmrg {
3601debfc3dSmrg edge e;
3611debfc3dSmrg edge_iterator ei;
3621debfc3dSmrg
3631debfc3dSmrg FOR_EACH_EDGE (e, ei, bb->succs)
3641debfc3dSmrg if (!EDGE_INFO (e)->ignore && !EDGE_INFO (e)->on_tree)
3651debfc3dSmrg {
3661debfc3dSmrg num_edges++;
3671debfc3dSmrg if (exec_counts)
368a2dc1f3fSmrg edge_gcov_count (e) = exec_counts[exec_counts_pos++];
3691debfc3dSmrg else
370a2dc1f3fSmrg edge_gcov_count (e) = 0;
3711debfc3dSmrg
3721debfc3dSmrg EDGE_INFO (e)->count_valid = 1;
3731debfc3dSmrg BB_INFO (bb)->succ_count--;
3741debfc3dSmrg BB_INFO (e->dest)->pred_count--;
3751debfc3dSmrg if (dump_file)
3761debfc3dSmrg {
3771debfc3dSmrg fprintf (dump_file, "\nRead edge from %i to %i, count:",
3781debfc3dSmrg bb->index, e->dest->index);
3791debfc3dSmrg fprintf (dump_file, "%" PRId64,
380a2dc1f3fSmrg (int64_t) edge_gcov_count (e));
3811debfc3dSmrg }
3821debfc3dSmrg }
3831debfc3dSmrg }
3841debfc3dSmrg
3851debfc3dSmrg return num_edges;
3861debfc3dSmrg }
3871debfc3dSmrg
3881debfc3dSmrg
3891debfc3dSmrg /* Compute the branch probabilities for the various branches.
3901debfc3dSmrg Annotate them accordingly.
3911debfc3dSmrg
3921debfc3dSmrg CFG_CHECKSUM is the precomputed checksum for the CFG. */
3931debfc3dSmrg
3941debfc3dSmrg static void
compute_branch_probabilities(unsigned cfg_checksum,unsigned lineno_checksum)3951debfc3dSmrg compute_branch_probabilities (unsigned cfg_checksum, unsigned lineno_checksum)
3961debfc3dSmrg {
3971debfc3dSmrg basic_block bb;
3981debfc3dSmrg int i;
3991debfc3dSmrg int num_edges = 0;
4001debfc3dSmrg int changes;
4011debfc3dSmrg int passes;
4021debfc3dSmrg int hist_br_prob[20];
4031debfc3dSmrg int num_branches;
4041debfc3dSmrg gcov_type *exec_counts = get_exec_counts (cfg_checksum, lineno_checksum);
4051debfc3dSmrg int inconsistent = 0;
4061debfc3dSmrg
4071debfc3dSmrg /* Very simple sanity checks so we catch bugs in our profiling code. */
4081debfc3dSmrg if (!profile_info)
409a2dc1f3fSmrg {
410a2dc1f3fSmrg if (dump_file)
411a2dc1f3fSmrg fprintf (dump_file, "Profile info is missing; giving up\n");
4121debfc3dSmrg return;
413a2dc1f3fSmrg }
414a2dc1f3fSmrg
415a2dc1f3fSmrg bb_gcov_counts.safe_grow_cleared (last_basic_block_for_fn (cfun));
416a2dc1f3fSmrg edge_gcov_counts = new hash_map<edge,gcov_type>;
4171debfc3dSmrg
4181debfc3dSmrg /* Attach extra info block to each bb. */
4191debfc3dSmrg alloc_aux_for_blocks (sizeof (struct bb_profile_info));
4201debfc3dSmrg FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun), NULL, next_bb)
4211debfc3dSmrg {
4221debfc3dSmrg edge e;
4231debfc3dSmrg edge_iterator ei;
4241debfc3dSmrg
4251debfc3dSmrg FOR_EACH_EDGE (e, ei, bb->succs)
4261debfc3dSmrg if (!EDGE_INFO (e)->ignore)
4271debfc3dSmrg BB_INFO (bb)->succ_count++;
4281debfc3dSmrg FOR_EACH_EDGE (e, ei, bb->preds)
4291debfc3dSmrg if (!EDGE_INFO (e)->ignore)
4301debfc3dSmrg BB_INFO (bb)->pred_count++;
4311debfc3dSmrg }
4321debfc3dSmrg
4331debfc3dSmrg /* Avoid predicting entry on exit nodes. */
4341debfc3dSmrg BB_INFO (EXIT_BLOCK_PTR_FOR_FN (cfun))->succ_count = 2;
4351debfc3dSmrg BB_INFO (ENTRY_BLOCK_PTR_FOR_FN (cfun))->pred_count = 2;
4361debfc3dSmrg
4371debfc3dSmrg num_edges = read_profile_edge_counts (exec_counts);
4381debfc3dSmrg
4391debfc3dSmrg if (dump_file)
4401debfc3dSmrg fprintf (dump_file, "\n%d edge counts read\n", num_edges);
4411debfc3dSmrg
4421debfc3dSmrg /* For every block in the file,
4431debfc3dSmrg - if every exit/entrance edge has a known count, then set the block count
4441debfc3dSmrg - if the block count is known, and every exit/entrance edge but one has
4451debfc3dSmrg a known execution count, then set the count of the remaining edge
4461debfc3dSmrg
4471debfc3dSmrg As edge counts are set, decrement the succ/pred count, but don't delete
4481debfc3dSmrg the edge, that way we can easily tell when all edges are known, or only
4491debfc3dSmrg one edge is unknown. */
4501debfc3dSmrg
4511debfc3dSmrg /* The order that the basic blocks are iterated through is important.
4521debfc3dSmrg Since the code that finds spanning trees starts with block 0, low numbered
4531debfc3dSmrg edges are put on the spanning tree in preference to high numbered edges.
4541debfc3dSmrg Hence, most instrumented edges are at the end. Graph solving works much
4551debfc3dSmrg faster if we propagate numbers from the end to the start.
4561debfc3dSmrg
4571debfc3dSmrg This takes an average of slightly more than 3 passes. */
4581debfc3dSmrg
4591debfc3dSmrg changes = 1;
4601debfc3dSmrg passes = 0;
4611debfc3dSmrg while (changes)
4621debfc3dSmrg {
4631debfc3dSmrg passes++;
4641debfc3dSmrg changes = 0;
4651debfc3dSmrg FOR_BB_BETWEEN (bb, EXIT_BLOCK_PTR_FOR_FN (cfun), NULL, prev_bb)
4661debfc3dSmrg {
4671debfc3dSmrg struct bb_profile_info *bi = BB_INFO (bb);
4681debfc3dSmrg if (! bi->count_valid)
4691debfc3dSmrg {
4701debfc3dSmrg if (bi->succ_count == 0)
4711debfc3dSmrg {
4721debfc3dSmrg edge e;
4731debfc3dSmrg edge_iterator ei;
4741debfc3dSmrg gcov_type total = 0;
4751debfc3dSmrg
4761debfc3dSmrg FOR_EACH_EDGE (e, ei, bb->succs)
477a2dc1f3fSmrg total += edge_gcov_count (e);
478a2dc1f3fSmrg bb_gcov_count (bb) = total;
4791debfc3dSmrg bi->count_valid = 1;
4801debfc3dSmrg changes = 1;
4811debfc3dSmrg }
4821debfc3dSmrg else if (bi->pred_count == 0)
4831debfc3dSmrg {
4841debfc3dSmrg edge e;
4851debfc3dSmrg edge_iterator ei;
4861debfc3dSmrg gcov_type total = 0;
4871debfc3dSmrg
4881debfc3dSmrg FOR_EACH_EDGE (e, ei, bb->preds)
489a2dc1f3fSmrg total += edge_gcov_count (e);
490a2dc1f3fSmrg bb_gcov_count (bb) = total;
4911debfc3dSmrg bi->count_valid = 1;
4921debfc3dSmrg changes = 1;
4931debfc3dSmrg }
4941debfc3dSmrg }
4951debfc3dSmrg if (bi->count_valid)
4961debfc3dSmrg {
4971debfc3dSmrg if (bi->succ_count == 1)
4981debfc3dSmrg {
4991debfc3dSmrg edge e;
5001debfc3dSmrg edge_iterator ei;
5011debfc3dSmrg gcov_type total = 0;
5021debfc3dSmrg
5031debfc3dSmrg /* One of the counts will be invalid, but it is zero,
5041debfc3dSmrg so adding it in also doesn't hurt. */
5051debfc3dSmrg FOR_EACH_EDGE (e, ei, bb->succs)
506a2dc1f3fSmrg total += edge_gcov_count (e);
5071debfc3dSmrg
5081debfc3dSmrg /* Search for the invalid edge, and set its count. */
5091debfc3dSmrg FOR_EACH_EDGE (e, ei, bb->succs)
5101debfc3dSmrg if (! EDGE_INFO (e)->count_valid && ! EDGE_INFO (e)->ignore)
5111debfc3dSmrg break;
5121debfc3dSmrg
5131debfc3dSmrg /* Calculate count for remaining edge by conservation. */
514a2dc1f3fSmrg total = bb_gcov_count (bb) - total;
5151debfc3dSmrg
5161debfc3dSmrg gcc_assert (e);
5171debfc3dSmrg EDGE_INFO (e)->count_valid = 1;
518a2dc1f3fSmrg edge_gcov_count (e) = total;
5191debfc3dSmrg bi->succ_count--;
5201debfc3dSmrg
5211debfc3dSmrg BB_INFO (e->dest)->pred_count--;
5221debfc3dSmrg changes = 1;
5231debfc3dSmrg }
5241debfc3dSmrg if (bi->pred_count == 1)
5251debfc3dSmrg {
5261debfc3dSmrg edge e;
5271debfc3dSmrg edge_iterator ei;
5281debfc3dSmrg gcov_type total = 0;
5291debfc3dSmrg
5301debfc3dSmrg /* One of the counts will be invalid, but it is zero,
5311debfc3dSmrg so adding it in also doesn't hurt. */
5321debfc3dSmrg FOR_EACH_EDGE (e, ei, bb->preds)
533a2dc1f3fSmrg total += edge_gcov_count (e);
5341debfc3dSmrg
5351debfc3dSmrg /* Search for the invalid edge, and set its count. */
5361debfc3dSmrg FOR_EACH_EDGE (e, ei, bb->preds)
5371debfc3dSmrg if (!EDGE_INFO (e)->count_valid && !EDGE_INFO (e)->ignore)
5381debfc3dSmrg break;
5391debfc3dSmrg
5401debfc3dSmrg /* Calculate count for remaining edge by conservation. */
541a2dc1f3fSmrg total = bb_gcov_count (bb) - total + edge_gcov_count (e);
5421debfc3dSmrg
5431debfc3dSmrg gcc_assert (e);
5441debfc3dSmrg EDGE_INFO (e)->count_valid = 1;
545a2dc1f3fSmrg edge_gcov_count (e) = total;
5461debfc3dSmrg bi->pred_count--;
5471debfc3dSmrg
5481debfc3dSmrg BB_INFO (e->src)->succ_count--;
5491debfc3dSmrg changes = 1;
5501debfc3dSmrg }
5511debfc3dSmrg }
5521debfc3dSmrg }
5531debfc3dSmrg }
5541debfc3dSmrg
5551debfc3dSmrg total_num_passes += passes;
5561debfc3dSmrg if (dump_file)
5571debfc3dSmrg fprintf (dump_file, "Graph solving took %d passes.\n\n", passes);
5581debfc3dSmrg
5591debfc3dSmrg /* If the graph has been correctly solved, every block will have a
5601debfc3dSmrg succ and pred count of zero. */
5611debfc3dSmrg FOR_EACH_BB_FN (bb, cfun)
5621debfc3dSmrg {
5631debfc3dSmrg gcc_assert (!BB_INFO (bb)->succ_count && !BB_INFO (bb)->pred_count);
5641debfc3dSmrg }
5651debfc3dSmrg
5661debfc3dSmrg /* Check for inconsistent basic block counts */
5671debfc3dSmrg inconsistent = is_inconsistent ();
5681debfc3dSmrg
5691debfc3dSmrg if (inconsistent)
5701debfc3dSmrg {
5711debfc3dSmrg if (flag_profile_correction)
5721debfc3dSmrg {
5731debfc3dSmrg /* Inconsistency detected. Make it flow-consistent. */
5741debfc3dSmrg static int informed = 0;
5751debfc3dSmrg if (dump_enabled_p () && informed == 0)
5761debfc3dSmrg {
5771debfc3dSmrg informed = 1;
578c0a68be4Smrg dump_printf_loc (MSG_NOTE,
579c0a68be4Smrg dump_user_location_t::from_location_t (input_location),
5801debfc3dSmrg "correcting inconsistent profile data\n");
5811debfc3dSmrg }
5821debfc3dSmrg correct_negative_edge_counts ();
5831debfc3dSmrg /* Set bb counts to the sum of the outgoing edge counts */
5841debfc3dSmrg set_bb_counts ();
5851debfc3dSmrg if (dump_file)
5861debfc3dSmrg fprintf (dump_file, "\nCalling mcf_smooth_cfg\n");
5871debfc3dSmrg mcf_smooth_cfg ();
5881debfc3dSmrg }
5891debfc3dSmrg else
5901debfc3dSmrg error ("corrupted profile info: profile data is not flow-consistent");
5911debfc3dSmrg }
5921debfc3dSmrg
5931debfc3dSmrg /* For every edge, calculate its branch probability and add a reg_note
5941debfc3dSmrg to the branch insn to indicate this. */
5951debfc3dSmrg
5961debfc3dSmrg for (i = 0; i < 20; i++)
5971debfc3dSmrg hist_br_prob[i] = 0;
5981debfc3dSmrg num_branches = 0;
5991debfc3dSmrg
6001debfc3dSmrg FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun), NULL, next_bb)
6011debfc3dSmrg {
6021debfc3dSmrg edge e;
6031debfc3dSmrg edge_iterator ei;
6041debfc3dSmrg
605a2dc1f3fSmrg if (bb_gcov_count (bb) < 0)
6061debfc3dSmrg {
6071debfc3dSmrg error ("corrupted profile info: number of iterations for basic block %d thought to be %i",
608a2dc1f3fSmrg bb->index, (int)bb_gcov_count (bb));
609a2dc1f3fSmrg bb_gcov_count (bb) = 0;
6101debfc3dSmrg }
6111debfc3dSmrg FOR_EACH_EDGE (e, ei, bb->succs)
6121debfc3dSmrg {
6131debfc3dSmrg /* Function may return twice in the cased the called function is
6141debfc3dSmrg setjmp or calls fork, but we can't represent this by extra
6151debfc3dSmrg edge from the entry, since extra edge from the exit is
6161debfc3dSmrg already present. We get negative frequency from the entry
6171debfc3dSmrg point. */
618a2dc1f3fSmrg if ((edge_gcov_count (e) < 0
6191debfc3dSmrg && e->dest == EXIT_BLOCK_PTR_FOR_FN (cfun))
620a2dc1f3fSmrg || (edge_gcov_count (e) > bb_gcov_count (bb)
6211debfc3dSmrg && e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun)))
6221debfc3dSmrg {
6231debfc3dSmrg if (block_ends_with_call_p (bb))
624a2dc1f3fSmrg edge_gcov_count (e) = edge_gcov_count (e) < 0
625a2dc1f3fSmrg ? 0 : bb_gcov_count (bb);
6261debfc3dSmrg }
627a2dc1f3fSmrg if (edge_gcov_count (e) < 0
628a2dc1f3fSmrg || edge_gcov_count (e) > bb_gcov_count (bb))
6291debfc3dSmrg {
6301debfc3dSmrg error ("corrupted profile info: number of executions for edge %d-%d thought to be %i",
6311debfc3dSmrg e->src->index, e->dest->index,
632a2dc1f3fSmrg (int)edge_gcov_count (e));
633a2dc1f3fSmrg edge_gcov_count (e) = bb_gcov_count (bb) / 2;
6341debfc3dSmrg }
6351debfc3dSmrg }
636a2dc1f3fSmrg if (bb_gcov_count (bb))
6371debfc3dSmrg {
638*8feb0f0bSmrg bool set_to_guessed = false;
6391debfc3dSmrg FOR_EACH_EDGE (e, ei, bb->succs)
640*8feb0f0bSmrg {
641*8feb0f0bSmrg bool prev_never = e->probability == profile_probability::never ();
642a2dc1f3fSmrg e->probability = profile_probability::probability_in_gcov_type
643a2dc1f3fSmrg (edge_gcov_count (e), bb_gcov_count (bb));
644*8feb0f0bSmrg if (e->probability == profile_probability::never ()
645*8feb0f0bSmrg && !prev_never
646*8feb0f0bSmrg && flag_profile_partial_training)
647*8feb0f0bSmrg set_to_guessed = true;
648*8feb0f0bSmrg }
649*8feb0f0bSmrg if (set_to_guessed)
650*8feb0f0bSmrg FOR_EACH_EDGE (e, ei, bb->succs)
651*8feb0f0bSmrg e->probability = e->probability.guessed ();
6521debfc3dSmrg if (bb->index >= NUM_FIXED_BLOCKS
6531debfc3dSmrg && block_ends_with_condjump_p (bb)
6541debfc3dSmrg && EDGE_COUNT (bb->succs) >= 2)
6551debfc3dSmrg {
6561debfc3dSmrg int prob;
6571debfc3dSmrg edge e;
6581debfc3dSmrg int index;
6591debfc3dSmrg
6601debfc3dSmrg /* Find the branch edge. It is possible that we do have fake
6611debfc3dSmrg edges here. */
6621debfc3dSmrg FOR_EACH_EDGE (e, ei, bb->succs)
6631debfc3dSmrg if (!(e->flags & (EDGE_FAKE | EDGE_FALLTHRU)))
6641debfc3dSmrg break;
6651debfc3dSmrg
666a2dc1f3fSmrg prob = e->probability.to_reg_br_prob_base ();
6671debfc3dSmrg index = prob * 20 / REG_BR_PROB_BASE;
6681debfc3dSmrg
6691debfc3dSmrg if (index == 20)
6701debfc3dSmrg index = 19;
6711debfc3dSmrg hist_br_prob[index]++;
6721debfc3dSmrg
6731debfc3dSmrg num_branches++;
6741debfc3dSmrg }
6751debfc3dSmrg }
6761debfc3dSmrg /* As a last resort, distribute the probabilities evenly.
6771debfc3dSmrg Use simple heuristics that if there are normal edges,
6781debfc3dSmrg give all abnormals frequency of 0, otherwise distribute the
6791debfc3dSmrg frequency over abnormals (this is the case of noreturn
6801debfc3dSmrg calls). */
6811debfc3dSmrg else if (profile_status_for_fn (cfun) == PROFILE_ABSENT)
6821debfc3dSmrg {
6831debfc3dSmrg int total = 0;
6841debfc3dSmrg
6851debfc3dSmrg FOR_EACH_EDGE (e, ei, bb->succs)
6861debfc3dSmrg if (!(e->flags & (EDGE_COMPLEX | EDGE_FAKE)))
6871debfc3dSmrg total ++;
6881debfc3dSmrg if (total)
6891debfc3dSmrg {
6901debfc3dSmrg FOR_EACH_EDGE (e, ei, bb->succs)
6911debfc3dSmrg if (!(e->flags & (EDGE_COMPLEX | EDGE_FAKE)))
692a2dc1f3fSmrg e->probability
693a2dc1f3fSmrg = profile_probability::guessed_always ().apply_scale (1, total);
6941debfc3dSmrg else
695a2dc1f3fSmrg e->probability = profile_probability::never ();
6961debfc3dSmrg }
6971debfc3dSmrg else
6981debfc3dSmrg {
6991debfc3dSmrg total += EDGE_COUNT (bb->succs);
7001debfc3dSmrg FOR_EACH_EDGE (e, ei, bb->succs)
701a2dc1f3fSmrg e->probability
702a2dc1f3fSmrg = profile_probability::guessed_always ().apply_scale (1, total);
7031debfc3dSmrg }
7041debfc3dSmrg if (bb->index >= NUM_FIXED_BLOCKS
7051debfc3dSmrg && block_ends_with_condjump_p (bb)
7061debfc3dSmrg && EDGE_COUNT (bb->succs) >= 2)
7071debfc3dSmrg num_branches++;
7081debfc3dSmrg }
7091debfc3dSmrg }
710a2dc1f3fSmrg
711*8feb0f0bSmrg if (exec_counts
712*8feb0f0bSmrg && (bb_gcov_count (ENTRY_BLOCK_PTR_FOR_FN (cfun))
713*8feb0f0bSmrg || !flag_profile_partial_training))
714c0a68be4Smrg profile_status_for_fn (cfun) = PROFILE_READ;
715c0a68be4Smrg
716a2dc1f3fSmrg /* If we have real data, use them! */
717a2dc1f3fSmrg if (bb_gcov_count (ENTRY_BLOCK_PTR_FOR_FN (cfun))
718a2dc1f3fSmrg || !flag_guess_branch_prob)
719a2dc1f3fSmrg FOR_ALL_BB_FN (bb, cfun)
720*8feb0f0bSmrg if (bb_gcov_count (bb) || !flag_profile_partial_training)
721a2dc1f3fSmrg bb->count = profile_count::from_gcov_type (bb_gcov_count (bb));
722*8feb0f0bSmrg else
723*8feb0f0bSmrg bb->count = profile_count::guessed_zero ();
724a2dc1f3fSmrg /* If function was not trained, preserve local estimates including statically
725a2dc1f3fSmrg determined zero counts. */
726*8feb0f0bSmrg else if (profile_status_for_fn (cfun) == PROFILE_READ
727*8feb0f0bSmrg && !flag_profile_partial_training)
728a2dc1f3fSmrg FOR_ALL_BB_FN (bb, cfun)
729a2dc1f3fSmrg if (!(bb->count == profile_count::zero ()))
730a2dc1f3fSmrg bb->count = bb->count.global0 ();
731a2dc1f3fSmrg
732a2dc1f3fSmrg bb_gcov_counts.release ();
733a2dc1f3fSmrg delete edge_gcov_counts;
734a2dc1f3fSmrg edge_gcov_counts = NULL;
735a2dc1f3fSmrg
736a2dc1f3fSmrg update_max_bb_count ();
7371debfc3dSmrg
7381debfc3dSmrg if (dump_file)
7391debfc3dSmrg {
740c0a68be4Smrg fprintf (dump_file, " Profile feedback for function");
741c0a68be4Smrg fprintf (dump_file, ((profile_status_for_fn (cfun) == PROFILE_READ)
742c0a68be4Smrg ? " is available \n"
743c0a68be4Smrg : " is not available \n"));
744c0a68be4Smrg
7451debfc3dSmrg fprintf (dump_file, "%d branches\n", num_branches);
7461debfc3dSmrg if (num_branches)
7471debfc3dSmrg for (i = 0; i < 10; i++)
7481debfc3dSmrg fprintf (dump_file, "%d%% branches in range %d-%d%%\n",
7491debfc3dSmrg (hist_br_prob[i] + hist_br_prob[19-i]) * 100 / num_branches,
7501debfc3dSmrg 5 * i, 5 * i + 5);
7511debfc3dSmrg
7521debfc3dSmrg total_num_branches += num_branches;
7531debfc3dSmrg for (i = 0; i < 20; i++)
7541debfc3dSmrg total_hist_br_prob[i] += hist_br_prob[i];
7551debfc3dSmrg
7561debfc3dSmrg fputc ('\n', dump_file);
7571debfc3dSmrg fputc ('\n', dump_file);
7581debfc3dSmrg }
7591debfc3dSmrg
7601debfc3dSmrg free_aux_for_blocks ();
7611debfc3dSmrg }
7621debfc3dSmrg
763*8feb0f0bSmrg /* Sort the histogram value and count for TOPN and INDIR_CALL type. */
764*8feb0f0bSmrg
765*8feb0f0bSmrg static void
sort_hist_values(histogram_value hist)766*8feb0f0bSmrg sort_hist_values (histogram_value hist)
767*8feb0f0bSmrg {
768*8feb0f0bSmrg /* counters[2] equal to -1 means that all counters are invalidated. */
769*8feb0f0bSmrg if (hist->hvalue.counters[2] == -1)
770*8feb0f0bSmrg return;
771*8feb0f0bSmrg
772*8feb0f0bSmrg gcc_assert (hist->type == HIST_TYPE_TOPN_VALUES
773*8feb0f0bSmrg || hist->type == HIST_TYPE_INDIR_CALL);
774*8feb0f0bSmrg
775*8feb0f0bSmrg gcc_assert (hist->n_counters == GCOV_TOPN_VALUES_COUNTERS);
776*8feb0f0bSmrg
777*8feb0f0bSmrg /* Hist value is organized as:
778*8feb0f0bSmrg [total_executions, value1, counter1, ..., value4, counter4]
779*8feb0f0bSmrg Use decrease bubble sort to rearrange it. The sort starts from <value1,
780*8feb0f0bSmrg counter1> and compares counter first. If counter is same, compares the
781*8feb0f0bSmrg value, exchange it if small to keep stable. */
782*8feb0f0bSmrg for (unsigned i = 0; i < GCOV_TOPN_VALUES - 1; i++)
783*8feb0f0bSmrg {
784*8feb0f0bSmrg bool swapped = false;
785*8feb0f0bSmrg for (unsigned j = 0; j < GCOV_TOPN_VALUES - 1 - i; j++)
786*8feb0f0bSmrg {
787*8feb0f0bSmrg gcov_type *p = &hist->hvalue.counters[2 * j + 1];
788*8feb0f0bSmrg if (p[1] < p[3] || (p[1] == p[3] && p[0] < p[2]))
789*8feb0f0bSmrg {
790*8feb0f0bSmrg std::swap (p[0], p[2]);
791*8feb0f0bSmrg std::swap (p[1], p[3]);
792*8feb0f0bSmrg swapped = true;
793*8feb0f0bSmrg }
794*8feb0f0bSmrg }
795*8feb0f0bSmrg if (!swapped)
796*8feb0f0bSmrg break;
797*8feb0f0bSmrg }
798*8feb0f0bSmrg }
7991debfc3dSmrg /* Load value histograms values whose description is stored in VALUES array
8001debfc3dSmrg from .gcda file.
8011debfc3dSmrg
8021debfc3dSmrg CFG_CHECKSUM is the precomputed checksum for the CFG. */
8031debfc3dSmrg
8041debfc3dSmrg static void
compute_value_histograms(histogram_values values,unsigned cfg_checksum,unsigned lineno_checksum)8051debfc3dSmrg compute_value_histograms (histogram_values values, unsigned cfg_checksum,
8061debfc3dSmrg unsigned lineno_checksum)
8071debfc3dSmrg {
8081debfc3dSmrg unsigned i, j, t, any;
8091debfc3dSmrg unsigned n_histogram_counters[GCOV_N_VALUE_COUNTERS];
8101debfc3dSmrg gcov_type *histogram_counts[GCOV_N_VALUE_COUNTERS];
8111debfc3dSmrg gcov_type *act_count[GCOV_N_VALUE_COUNTERS];
8121debfc3dSmrg gcov_type *aact_count;
8131debfc3dSmrg struct cgraph_node *node;
8141debfc3dSmrg
8151debfc3dSmrg for (t = 0; t < GCOV_N_VALUE_COUNTERS; t++)
8161debfc3dSmrg n_histogram_counters[t] = 0;
8171debfc3dSmrg
8181debfc3dSmrg for (i = 0; i < values.length (); i++)
8191debfc3dSmrg {
8201debfc3dSmrg histogram_value hist = values[i];
8211debfc3dSmrg n_histogram_counters[(int) hist->type] += hist->n_counters;
8221debfc3dSmrg }
8231debfc3dSmrg
8241debfc3dSmrg any = 0;
8251debfc3dSmrg for (t = 0; t < GCOV_N_VALUE_COUNTERS; t++)
8261debfc3dSmrg {
8271debfc3dSmrg if (!n_histogram_counters[t])
8281debfc3dSmrg {
8291debfc3dSmrg histogram_counts[t] = NULL;
8301debfc3dSmrg continue;
8311debfc3dSmrg }
8321debfc3dSmrg
833c0a68be4Smrg histogram_counts[t] = get_coverage_counts (COUNTER_FOR_HIST_TYPE (t),
834c0a68be4Smrg cfg_checksum,
835c0a68be4Smrg lineno_checksum,
836c0a68be4Smrg n_histogram_counters[t]);
8371debfc3dSmrg if (histogram_counts[t])
8381debfc3dSmrg any = 1;
8391debfc3dSmrg act_count[t] = histogram_counts[t];
8401debfc3dSmrg }
8411debfc3dSmrg if (!any)
8421debfc3dSmrg return;
8431debfc3dSmrg
8441debfc3dSmrg for (i = 0; i < values.length (); i++)
8451debfc3dSmrg {
8461debfc3dSmrg histogram_value hist = values[i];
8471debfc3dSmrg gimple *stmt = hist->hvalue.stmt;
8481debfc3dSmrg
8491debfc3dSmrg t = (int) hist->type;
8501debfc3dSmrg
8511debfc3dSmrg aact_count = act_count[t];
8521debfc3dSmrg
8531debfc3dSmrg if (act_count[t])
8541debfc3dSmrg act_count[t] += hist->n_counters;
8551debfc3dSmrg
8561debfc3dSmrg gimple_add_histogram_value (cfun, stmt, hist);
8571debfc3dSmrg hist->hvalue.counters = XNEWVEC (gcov_type, hist->n_counters);
8581debfc3dSmrg for (j = 0; j < hist->n_counters; j++)
8591debfc3dSmrg if (aact_count)
8601debfc3dSmrg hist->hvalue.counters[j] = aact_count[j];
8611debfc3dSmrg else
8621debfc3dSmrg hist->hvalue.counters[j] = 0;
8631debfc3dSmrg
864*8feb0f0bSmrg if (hist->type == HIST_TYPE_TOPN_VALUES
865*8feb0f0bSmrg || hist->type == HIST_TYPE_INDIR_CALL)
866*8feb0f0bSmrg {
867*8feb0f0bSmrg /* Each count value is multiplied by GCOV_TOPN_VALUES. */
868*8feb0f0bSmrg if (hist->hvalue.counters[2] != -1)
869*8feb0f0bSmrg for (unsigned i = 0; i < GCOV_TOPN_VALUES; i++)
870*8feb0f0bSmrg hist->hvalue.counters[2 * i + 2]
871*8feb0f0bSmrg = RDIV (hist->hvalue.counters[2 * i + 2], GCOV_TOPN_VALUES);
872*8feb0f0bSmrg
873*8feb0f0bSmrg sort_hist_values (hist);
874*8feb0f0bSmrg }
875*8feb0f0bSmrg
8761debfc3dSmrg /* Time profiler counter is not related to any statement,
8771debfc3dSmrg so that we have to read the counter and set the value to
8781debfc3dSmrg the corresponding call graph node. */
8791debfc3dSmrg if (hist->type == HIST_TYPE_TIME_PROFILE)
8801debfc3dSmrg {
8811debfc3dSmrg node = cgraph_node::get (hist->fun->decl);
882*8feb0f0bSmrg if (hist->hvalue.counters[0] >= 0
883*8feb0f0bSmrg && hist->hvalue.counters[0] < INT_MAX / 2)
8841debfc3dSmrg node->tp_first_run = hist->hvalue.counters[0];
885*8feb0f0bSmrg else
886*8feb0f0bSmrg {
887*8feb0f0bSmrg if (flag_profile_correction)
888*8feb0f0bSmrg error ("corrupted profile info: invalid time profile");
889*8feb0f0bSmrg node->tp_first_run = 0;
890*8feb0f0bSmrg }
8911debfc3dSmrg
8921debfc3dSmrg if (dump_file)
8931debfc3dSmrg fprintf (dump_file, "Read tp_first_run: %d\n", node->tp_first_run);
8941debfc3dSmrg }
8951debfc3dSmrg }
8961debfc3dSmrg
8971debfc3dSmrg for (t = 0; t < GCOV_N_VALUE_COUNTERS; t++)
8981debfc3dSmrg free (histogram_counts[t]);
8991debfc3dSmrg }
9001debfc3dSmrg
901c0a68be4Smrg /* Location triplet which records a location. */
902c0a68be4Smrg struct location_triplet
903c0a68be4Smrg {
904c0a68be4Smrg const char *filename;
905c0a68be4Smrg int lineno;
906c0a68be4Smrg int bb_index;
907c0a68be4Smrg };
908c0a68be4Smrg
909c0a68be4Smrg /* Traits class for streamed_locations hash set below. */
910c0a68be4Smrg
911c0a68be4Smrg struct location_triplet_hash : typed_noop_remove <location_triplet>
912c0a68be4Smrg {
913c0a68be4Smrg typedef location_triplet value_type;
914c0a68be4Smrg typedef location_triplet compare_type;
915c0a68be4Smrg
916c0a68be4Smrg static hashval_t
hashlocation_triplet_hash917c0a68be4Smrg hash (const location_triplet &ref)
918c0a68be4Smrg {
919c0a68be4Smrg inchash::hash hstate (0);
920c0a68be4Smrg if (ref.filename)
921c0a68be4Smrg hstate.add_int (strlen (ref.filename));
922c0a68be4Smrg hstate.add_int (ref.lineno);
923c0a68be4Smrg hstate.add_int (ref.bb_index);
924c0a68be4Smrg return hstate.end ();
925c0a68be4Smrg }
926c0a68be4Smrg
927c0a68be4Smrg static bool
equallocation_triplet_hash928c0a68be4Smrg equal (const location_triplet &ref1, const location_triplet &ref2)
929c0a68be4Smrg {
930c0a68be4Smrg return ref1.lineno == ref2.lineno
931c0a68be4Smrg && ref1.bb_index == ref2.bb_index
932c0a68be4Smrg && ref1.filename != NULL
933c0a68be4Smrg && ref2.filename != NULL
934c0a68be4Smrg && strcmp (ref1.filename, ref2.filename) == 0;
935c0a68be4Smrg }
936c0a68be4Smrg
937c0a68be4Smrg static void
mark_deletedlocation_triplet_hash938c0a68be4Smrg mark_deleted (location_triplet &ref)
939c0a68be4Smrg {
940c0a68be4Smrg ref.lineno = -1;
941c0a68be4Smrg }
942c0a68be4Smrg
943*8feb0f0bSmrg static const bool empty_zero_p = false;
944*8feb0f0bSmrg
945c0a68be4Smrg static void
mark_emptylocation_triplet_hash946c0a68be4Smrg mark_empty (location_triplet &ref)
947c0a68be4Smrg {
948c0a68be4Smrg ref.lineno = -2;
949c0a68be4Smrg }
950c0a68be4Smrg
951c0a68be4Smrg static bool
is_deletedlocation_triplet_hash952c0a68be4Smrg is_deleted (const location_triplet &ref)
953c0a68be4Smrg {
954c0a68be4Smrg return ref.lineno == -1;
955c0a68be4Smrg }
956c0a68be4Smrg
957c0a68be4Smrg static bool
is_emptylocation_triplet_hash958c0a68be4Smrg is_empty (const location_triplet &ref)
959c0a68be4Smrg {
960c0a68be4Smrg return ref.lineno == -2;
961c0a68be4Smrg }
962c0a68be4Smrg };
963c0a68be4Smrg
964c0a68be4Smrg
965c0a68be4Smrg
966c0a68be4Smrg
9671debfc3dSmrg /* When passed NULL as file_name, initialize.
9681debfc3dSmrg When passed something else, output the necessary commands to change
9691debfc3dSmrg line to LINE and offset to FILE_NAME. */
9701debfc3dSmrg static void
output_location(hash_set<location_triplet_hash> * streamed_locations,char const * file_name,int line,gcov_position_t * offset,basic_block bb)971c0a68be4Smrg output_location (hash_set<location_triplet_hash> *streamed_locations,
972c0a68be4Smrg char const *file_name, int line,
9731debfc3dSmrg gcov_position_t *offset, basic_block bb)
9741debfc3dSmrg {
9751debfc3dSmrg static char const *prev_file_name;
9761debfc3dSmrg static int prev_line;
9771debfc3dSmrg bool name_differs, line_differs;
9781debfc3dSmrg
979c0a68be4Smrg location_triplet triplet;
980c0a68be4Smrg triplet.filename = file_name;
981c0a68be4Smrg triplet.lineno = line;
982c0a68be4Smrg triplet.bb_index = bb ? bb->index : 0;
983c0a68be4Smrg
984c0a68be4Smrg if (streamed_locations->add (triplet))
985c0a68be4Smrg return;
986c0a68be4Smrg
9871debfc3dSmrg if (!file_name)
9881debfc3dSmrg {
9891debfc3dSmrg prev_file_name = NULL;
9901debfc3dSmrg prev_line = -1;
9911debfc3dSmrg return;
9921debfc3dSmrg }
9931debfc3dSmrg
9941debfc3dSmrg name_differs = !prev_file_name || filename_cmp (file_name, prev_file_name);
9951debfc3dSmrg line_differs = prev_line != line;
9961debfc3dSmrg
9971debfc3dSmrg if (!*offset)
9981debfc3dSmrg {
9991debfc3dSmrg *offset = gcov_write_tag (GCOV_TAG_LINES);
10001debfc3dSmrg gcov_write_unsigned (bb->index);
10011debfc3dSmrg name_differs = line_differs = true;
10021debfc3dSmrg }
10031debfc3dSmrg
10041debfc3dSmrg /* If this is a new source file, then output the
10051debfc3dSmrg file's name to the .bb file. */
10061debfc3dSmrg if (name_differs)
10071debfc3dSmrg {
10081debfc3dSmrg prev_file_name = file_name;
10091debfc3dSmrg gcov_write_unsigned (0);
1010a2dc1f3fSmrg gcov_write_filename (prev_file_name);
10111debfc3dSmrg }
10121debfc3dSmrg if (line_differs)
10131debfc3dSmrg {
10141debfc3dSmrg gcov_write_unsigned (line);
10151debfc3dSmrg prev_line = line;
10161debfc3dSmrg }
10171debfc3dSmrg }
1018a2dc1f3fSmrg
1019a2dc1f3fSmrg /* Helper for qsort so edges get sorted from highest frequency to smallest.
1020a2dc1f3fSmrg This controls the weight for minimal spanning tree algorithm */
1021a2dc1f3fSmrg static int
compare_freqs(const void * p1,const void * p2)1022a2dc1f3fSmrg compare_freqs (const void *p1, const void *p2)
1023a2dc1f3fSmrg {
1024a2dc1f3fSmrg const_edge e1 = *(const const_edge *)p1;
1025a2dc1f3fSmrg const_edge e2 = *(const const_edge *)p2;
1026a2dc1f3fSmrg
1027a2dc1f3fSmrg /* Critical edges needs to be split which introduce extra control flow.
1028a2dc1f3fSmrg Make them more heavy. */
1029a2dc1f3fSmrg int m1 = EDGE_CRITICAL_P (e1) ? 2 : 1;
1030a2dc1f3fSmrg int m2 = EDGE_CRITICAL_P (e2) ? 2 : 1;
1031a2dc1f3fSmrg
1032a2dc1f3fSmrg if (EDGE_FREQUENCY (e1) * m1 + m1 != EDGE_FREQUENCY (e2) * m2 + m2)
1033a2dc1f3fSmrg return EDGE_FREQUENCY (e2) * m2 + m2 - EDGE_FREQUENCY (e1) * m1 - m1;
1034a2dc1f3fSmrg /* Stabilize sort. */
1035a2dc1f3fSmrg if (e1->src->index != e2->src->index)
1036a2dc1f3fSmrg return e2->src->index - e1->src->index;
1037a2dc1f3fSmrg return e2->dest->index - e1->dest->index;
10381debfc3dSmrg }
10391debfc3dSmrg
1040a2dc1f3fSmrg /* Only read execution count for thunks. */
1041a2dc1f3fSmrg
1042a2dc1f3fSmrg void
read_thunk_profile(struct cgraph_node * node)1043a2dc1f3fSmrg read_thunk_profile (struct cgraph_node *node)
1044a2dc1f3fSmrg {
1045a2dc1f3fSmrg tree old = current_function_decl;
1046a2dc1f3fSmrg current_function_decl = node->decl;
1047c0a68be4Smrg gcov_type *counts = get_coverage_counts (GCOV_COUNTER_ARCS, 0, 0, 1);
1048a2dc1f3fSmrg if (counts)
1049a2dc1f3fSmrg {
1050a2dc1f3fSmrg node->callees->count = node->count
1051a2dc1f3fSmrg = profile_count::from_gcov_type (counts[0]);
1052a2dc1f3fSmrg free (counts);
1053a2dc1f3fSmrg }
1054a2dc1f3fSmrg current_function_decl = old;
1055a2dc1f3fSmrg return;
1056a2dc1f3fSmrg }
1057a2dc1f3fSmrg
1058a2dc1f3fSmrg
10591debfc3dSmrg /* Instrument and/or analyze program behavior based on program the CFG.
10601debfc3dSmrg
10611debfc3dSmrg This function creates a representation of the control flow graph (of
10621debfc3dSmrg the function being compiled) that is suitable for the instrumentation
10631debfc3dSmrg of edges and/or converting measured edge counts to counts on the
10641debfc3dSmrg complete CFG.
10651debfc3dSmrg
10661debfc3dSmrg When FLAG_PROFILE_ARCS is nonzero, this function instruments the edges in
10671debfc3dSmrg the flow graph that are needed to reconstruct the dynamic behavior of the
10681debfc3dSmrg flow graph. This data is written to the gcno file for gcov.
10691debfc3dSmrg
10701debfc3dSmrg When FLAG_BRANCH_PROBABILITIES is nonzero, this function reads auxiliary
10711debfc3dSmrg information from the gcda file containing edge count information from
10721debfc3dSmrg previous executions of the function being compiled. In this case, the
10731debfc3dSmrg control flow graph is annotated with actual execution counts by
10741debfc3dSmrg compute_branch_probabilities().
10751debfc3dSmrg
10761debfc3dSmrg Main entry point of this file. */
10771debfc3dSmrg
10781debfc3dSmrg void
branch_prob(bool thunk)1079a2dc1f3fSmrg branch_prob (bool thunk)
10801debfc3dSmrg {
10811debfc3dSmrg basic_block bb;
10821debfc3dSmrg unsigned i;
10831debfc3dSmrg unsigned num_edges, ignored_edges;
10841debfc3dSmrg unsigned num_instrumented;
10851debfc3dSmrg struct edge_list *el;
10861debfc3dSmrg histogram_values values = histogram_values ();
10871debfc3dSmrg unsigned cfg_checksum, lineno_checksum;
10881debfc3dSmrg
10891debfc3dSmrg total_num_times_called++;
10901debfc3dSmrg
10911debfc3dSmrg flow_call_edges_add (NULL);
10921debfc3dSmrg add_noreturn_fake_exit_edges ();
10931debfc3dSmrg
1094c0a68be4Smrg hash_set <location_triplet_hash> streamed_locations;
1095c0a68be4Smrg
1096a2dc1f3fSmrg if (!thunk)
1097a2dc1f3fSmrg {
10981debfc3dSmrg /* We can't handle cyclic regions constructed using abnormal edges.
10991debfc3dSmrg To avoid these we replace every source of abnormal edge by a fake
11001debfc3dSmrg edge from entry node and every destination by fake edge to exit.
11011debfc3dSmrg This keeps graph acyclic and our calculation exact for all normal
11021debfc3dSmrg edges except for exit and entrance ones.
11031debfc3dSmrg
11041debfc3dSmrg We also add fake exit edges for each call and asm statement in the
11051debfc3dSmrg basic, since it may not return. */
11061debfc3dSmrg
11071debfc3dSmrg FOR_EACH_BB_FN (bb, cfun)
11081debfc3dSmrg {
11091debfc3dSmrg int need_exit_edge = 0, need_entry_edge = 0;
11101debfc3dSmrg int have_exit_edge = 0, have_entry_edge = 0;
11111debfc3dSmrg edge e;
11121debfc3dSmrg edge_iterator ei;
11131debfc3dSmrg
11141debfc3dSmrg /* Functions returning multiple times are not handled by extra edges.
11151debfc3dSmrg Instead we simply allow negative counts on edges from exit to the
11161debfc3dSmrg block past call and corresponding probabilities. We can't go
11171debfc3dSmrg with the extra edges because that would result in flowgraph that
11181debfc3dSmrg needs to have fake edges outside the spanning tree. */
11191debfc3dSmrg
11201debfc3dSmrg FOR_EACH_EDGE (e, ei, bb->succs)
11211debfc3dSmrg {
11221debfc3dSmrg gimple_stmt_iterator gsi;
11231debfc3dSmrg gimple *last = NULL;
11241debfc3dSmrg
11251debfc3dSmrg /* It may happen that there are compiler generated statements
11261debfc3dSmrg without a locus at all. Go through the basic block from the
11271debfc3dSmrg last to the first statement looking for a locus. */
11281debfc3dSmrg for (gsi = gsi_last_nondebug_bb (bb);
11291debfc3dSmrg !gsi_end_p (gsi);
11301debfc3dSmrg gsi_prev_nondebug (&gsi))
11311debfc3dSmrg {
11321debfc3dSmrg last = gsi_stmt (gsi);
11331debfc3dSmrg if (!RESERVED_LOCATION_P (gimple_location (last)))
11341debfc3dSmrg break;
11351debfc3dSmrg }
11361debfc3dSmrg
11371debfc3dSmrg /* Edge with goto locus might get wrong coverage info unless
11381debfc3dSmrg it is the only edge out of BB.
11391debfc3dSmrg Don't do that when the locuses match, so
11401debfc3dSmrg if (blah) goto something;
11411debfc3dSmrg is not computed twice. */
11421debfc3dSmrg if (last
11431debfc3dSmrg && gimple_has_location (last)
11441debfc3dSmrg && !RESERVED_LOCATION_P (e->goto_locus)
11451debfc3dSmrg && !single_succ_p (bb)
11461debfc3dSmrg && (LOCATION_FILE (e->goto_locus)
11471debfc3dSmrg != LOCATION_FILE (gimple_location (last))
11481debfc3dSmrg || (LOCATION_LINE (e->goto_locus)
11491debfc3dSmrg != LOCATION_LINE (gimple_location (last)))))
11501debfc3dSmrg {
11511debfc3dSmrg basic_block new_bb = split_edge (e);
11521debfc3dSmrg edge ne = single_succ_edge (new_bb);
11531debfc3dSmrg ne->goto_locus = e->goto_locus;
11541debfc3dSmrg }
11551debfc3dSmrg if ((e->flags & (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL))
11561debfc3dSmrg && e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun))
11571debfc3dSmrg need_exit_edge = 1;
11581debfc3dSmrg if (e->dest == EXIT_BLOCK_PTR_FOR_FN (cfun))
11591debfc3dSmrg have_exit_edge = 1;
11601debfc3dSmrg }
11611debfc3dSmrg FOR_EACH_EDGE (e, ei, bb->preds)
11621debfc3dSmrg {
11631debfc3dSmrg if ((e->flags & (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL))
11641debfc3dSmrg && e->src != ENTRY_BLOCK_PTR_FOR_FN (cfun))
11651debfc3dSmrg need_entry_edge = 1;
11661debfc3dSmrg if (e->src == ENTRY_BLOCK_PTR_FOR_FN (cfun))
11671debfc3dSmrg have_entry_edge = 1;
11681debfc3dSmrg }
11691debfc3dSmrg
11701debfc3dSmrg if (need_exit_edge && !have_exit_edge)
11711debfc3dSmrg {
11721debfc3dSmrg if (dump_file)
11731debfc3dSmrg fprintf (dump_file, "Adding fake exit edge to bb %i\n",
11741debfc3dSmrg bb->index);
11751debfc3dSmrg make_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun), EDGE_FAKE);
11761debfc3dSmrg }
11771debfc3dSmrg if (need_entry_edge && !have_entry_edge)
11781debfc3dSmrg {
11791debfc3dSmrg if (dump_file)
11801debfc3dSmrg fprintf (dump_file, "Adding fake entry edge to bb %i\n",
11811debfc3dSmrg bb->index);
11821debfc3dSmrg make_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun), bb, EDGE_FAKE);
11831debfc3dSmrg /* Avoid bbs that have both fake entry edge and also some
11841debfc3dSmrg exit edge. One of those edges wouldn't be added to the
11851debfc3dSmrg spanning tree, but we can't instrument any of them. */
11861debfc3dSmrg if (have_exit_edge || need_exit_edge)
11871debfc3dSmrg {
11881debfc3dSmrg gimple_stmt_iterator gsi;
11891debfc3dSmrg gimple *first;
11901debfc3dSmrg
11911debfc3dSmrg gsi = gsi_start_nondebug_after_labels_bb (bb);
11921debfc3dSmrg gcc_checking_assert (!gsi_end_p (gsi));
11931debfc3dSmrg first = gsi_stmt (gsi);
11941debfc3dSmrg /* Don't split the bbs containing __builtin_setjmp_receiver
11951debfc3dSmrg or ABNORMAL_DISPATCHER calls. These are very
11961debfc3dSmrg special and don't expect anything to be inserted before
11971debfc3dSmrg them. */
11981debfc3dSmrg if (is_gimple_call (first)
11991debfc3dSmrg && (gimple_call_builtin_p (first, BUILT_IN_SETJMP_RECEIVER)
12001debfc3dSmrg || (gimple_call_flags (first) & ECF_RETURNS_TWICE)
12011debfc3dSmrg || (gimple_call_internal_p (first)
12021debfc3dSmrg && (gimple_call_internal_fn (first)
12031debfc3dSmrg == IFN_ABNORMAL_DISPATCHER))))
12041debfc3dSmrg continue;
12051debfc3dSmrg
12061debfc3dSmrg if (dump_file)
12071debfc3dSmrg fprintf (dump_file, "Splitting bb %i after labels\n",
12081debfc3dSmrg bb->index);
12091debfc3dSmrg split_block_after_labels (bb);
12101debfc3dSmrg }
12111debfc3dSmrg }
12121debfc3dSmrg }
1213a2dc1f3fSmrg }
12141debfc3dSmrg
12151debfc3dSmrg el = create_edge_list ();
12161debfc3dSmrg num_edges = NUM_EDGES (el);
1217a2dc1f3fSmrg qsort (el->index_to_edge, num_edges, sizeof (edge), compare_freqs);
12181debfc3dSmrg alloc_aux_for_edges (sizeof (struct edge_profile_info));
12191debfc3dSmrg
12201debfc3dSmrg /* The basic blocks are expected to be numbered sequentially. */
12211debfc3dSmrg compact_blocks ();
12221debfc3dSmrg
12231debfc3dSmrg ignored_edges = 0;
12241debfc3dSmrg for (i = 0 ; i < num_edges ; i++)
12251debfc3dSmrg {
12261debfc3dSmrg edge e = INDEX_EDGE (el, i);
12271debfc3dSmrg
12281debfc3dSmrg /* Mark edges we've replaced by fake edges above as ignored. */
12291debfc3dSmrg if ((e->flags & (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL))
12301debfc3dSmrg && e->src != ENTRY_BLOCK_PTR_FOR_FN (cfun)
12311debfc3dSmrg && e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun))
12321debfc3dSmrg {
12331debfc3dSmrg EDGE_INFO (e)->ignore = 1;
12341debfc3dSmrg ignored_edges++;
12351debfc3dSmrg }
12361debfc3dSmrg }
12371debfc3dSmrg
12381debfc3dSmrg /* Create spanning tree from basic block graph, mark each edge that is
12391debfc3dSmrg on the spanning tree. We insert as many abnormal and critical edges
12401debfc3dSmrg as possible to minimize number of edge splits necessary. */
12411debfc3dSmrg
1242a2dc1f3fSmrg if (!thunk)
12431debfc3dSmrg find_spanning_tree (el);
1244a2dc1f3fSmrg else
1245a2dc1f3fSmrg {
1246a2dc1f3fSmrg edge e;
1247a2dc1f3fSmrg edge_iterator ei;
1248a2dc1f3fSmrg /* Keep only edge from entry block to be instrumented. */
1249a2dc1f3fSmrg FOR_EACH_BB_FN (bb, cfun)
1250a2dc1f3fSmrg FOR_EACH_EDGE (e, ei, bb->succs)
1251a2dc1f3fSmrg EDGE_INFO (e)->ignore = true;
1252a2dc1f3fSmrg }
1253a2dc1f3fSmrg
12541debfc3dSmrg
12551debfc3dSmrg /* Fake edges that are not on the tree will not be instrumented, so
12561debfc3dSmrg mark them ignored. */
12571debfc3dSmrg for (num_instrumented = i = 0; i < num_edges; i++)
12581debfc3dSmrg {
12591debfc3dSmrg edge e = INDEX_EDGE (el, i);
12601debfc3dSmrg struct edge_profile_info *inf = EDGE_INFO (e);
12611debfc3dSmrg
12621debfc3dSmrg if (inf->ignore || inf->on_tree)
12631debfc3dSmrg /*NOP*/;
12641debfc3dSmrg else if (e->flags & EDGE_FAKE)
12651debfc3dSmrg {
12661debfc3dSmrg inf->ignore = 1;
12671debfc3dSmrg ignored_edges++;
12681debfc3dSmrg }
12691debfc3dSmrg else
12701debfc3dSmrg num_instrumented++;
12711debfc3dSmrg }
12721debfc3dSmrg
12731debfc3dSmrg total_num_blocks += n_basic_blocks_for_fn (cfun);
12741debfc3dSmrg if (dump_file)
12751debfc3dSmrg fprintf (dump_file, "%d basic blocks\n", n_basic_blocks_for_fn (cfun));
12761debfc3dSmrg
12771debfc3dSmrg total_num_edges += num_edges;
12781debfc3dSmrg if (dump_file)
12791debfc3dSmrg fprintf (dump_file, "%d edges\n", num_edges);
12801debfc3dSmrg
12811debfc3dSmrg total_num_edges_ignored += ignored_edges;
12821debfc3dSmrg if (dump_file)
12831debfc3dSmrg fprintf (dump_file, "%d ignored edges\n", ignored_edges);
12841debfc3dSmrg
12851debfc3dSmrg total_num_edges_instrumented += num_instrumented;
12861debfc3dSmrg if (dump_file)
12871debfc3dSmrg fprintf (dump_file, "%d instrumentation edges\n", num_instrumented);
12881debfc3dSmrg
12891debfc3dSmrg /* Compute two different checksums. Note that we want to compute
12901debfc3dSmrg the checksum in only once place, since it depends on the shape
12911debfc3dSmrg of the control flow which can change during
12921debfc3dSmrg various transformations. */
1293a2dc1f3fSmrg if (thunk)
1294a2dc1f3fSmrg {
1295a2dc1f3fSmrg /* At stream in time we do not have CFG, so we cannot do checksums. */
1296a2dc1f3fSmrg cfg_checksum = 0;
1297a2dc1f3fSmrg lineno_checksum = 0;
1298a2dc1f3fSmrg }
1299a2dc1f3fSmrg else
1300a2dc1f3fSmrg {
13011debfc3dSmrg cfg_checksum = coverage_compute_cfg_checksum (cfun);
13021debfc3dSmrg lineno_checksum = coverage_compute_lineno_checksum ();
1303a2dc1f3fSmrg }
13041debfc3dSmrg
13051debfc3dSmrg /* Write the data from which gcov can reconstruct the basic block
13061debfc3dSmrg graph and function line numbers (the gcno file). */
13071debfc3dSmrg if (coverage_begin_function (lineno_checksum, cfg_checksum))
13081debfc3dSmrg {
13091debfc3dSmrg gcov_position_t offset;
13101debfc3dSmrg
13111debfc3dSmrg /* Basic block flags */
13121debfc3dSmrg offset = gcov_write_tag (GCOV_TAG_BLOCKS);
1313a2dc1f3fSmrg gcov_write_unsigned (n_basic_blocks_for_fn (cfun));
13141debfc3dSmrg gcov_write_length (offset);
13151debfc3dSmrg
13161debfc3dSmrg /* Arcs */
13171debfc3dSmrg FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun),
13181debfc3dSmrg EXIT_BLOCK_PTR_FOR_FN (cfun), next_bb)
13191debfc3dSmrg {
13201debfc3dSmrg edge e;
13211debfc3dSmrg edge_iterator ei;
13221debfc3dSmrg
13231debfc3dSmrg offset = gcov_write_tag (GCOV_TAG_ARCS);
13241debfc3dSmrg gcov_write_unsigned (bb->index);
13251debfc3dSmrg
13261debfc3dSmrg FOR_EACH_EDGE (e, ei, bb->succs)
13271debfc3dSmrg {
13281debfc3dSmrg struct edge_profile_info *i = EDGE_INFO (e);
13291debfc3dSmrg if (!i->ignore)
13301debfc3dSmrg {
13311debfc3dSmrg unsigned flag_bits = 0;
13321debfc3dSmrg
13331debfc3dSmrg if (i->on_tree)
13341debfc3dSmrg flag_bits |= GCOV_ARC_ON_TREE;
13351debfc3dSmrg if (e->flags & EDGE_FAKE)
13361debfc3dSmrg flag_bits |= GCOV_ARC_FAKE;
13371debfc3dSmrg if (e->flags & EDGE_FALLTHRU)
13381debfc3dSmrg flag_bits |= GCOV_ARC_FALLTHROUGH;
13391debfc3dSmrg /* On trees we don't have fallthru flags, but we can
13401debfc3dSmrg recompute them from CFG shape. */
13411debfc3dSmrg if (e->flags & (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE)
13421debfc3dSmrg && e->src->next_bb == e->dest)
13431debfc3dSmrg flag_bits |= GCOV_ARC_FALLTHROUGH;
13441debfc3dSmrg
13451debfc3dSmrg gcov_write_unsigned (e->dest->index);
13461debfc3dSmrg gcov_write_unsigned (flag_bits);
13471debfc3dSmrg }
13481debfc3dSmrg }
13491debfc3dSmrg
13501debfc3dSmrg gcov_write_length (offset);
13511debfc3dSmrg }
13521debfc3dSmrg
13531debfc3dSmrg /* Line numbers. */
13541debfc3dSmrg /* Initialize the output. */
1355c0a68be4Smrg output_location (&streamed_locations, NULL, 0, NULL, NULL);
1356c0a68be4Smrg
1357c0a68be4Smrg hash_set<int_hash <location_t, 0, 2> > seen_locations;
13581debfc3dSmrg
13591debfc3dSmrg FOR_EACH_BB_FN (bb, cfun)
13601debfc3dSmrg {
13611debfc3dSmrg gimple_stmt_iterator gsi;
13621debfc3dSmrg gcov_position_t offset = 0;
13631debfc3dSmrg
13641debfc3dSmrg if (bb == ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb)
13651debfc3dSmrg {
1366c0a68be4Smrg location_t loc = DECL_SOURCE_LOCATION (current_function_decl);
1367c0a68be4Smrg seen_locations.add (loc);
1368c0a68be4Smrg expanded_location curr_location = expand_location (loc);
1369c0a68be4Smrg output_location (&streamed_locations, curr_location.file,
1370*8feb0f0bSmrg MAX (1, curr_location.line), &offset, bb);
13711debfc3dSmrg }
13721debfc3dSmrg
13731debfc3dSmrg for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
13741debfc3dSmrg {
13751debfc3dSmrg gimple *stmt = gsi_stmt (gsi);
1376c0a68be4Smrg location_t loc = gimple_location (stmt);
1377c0a68be4Smrg if (!RESERVED_LOCATION_P (loc))
1378c0a68be4Smrg {
1379c0a68be4Smrg seen_locations.add (loc);
1380c0a68be4Smrg output_location (&streamed_locations, gimple_filename (stmt),
1381*8feb0f0bSmrg MAX (1, gimple_lineno (stmt)), &offset, bb);
1382c0a68be4Smrg }
13831debfc3dSmrg }
13841debfc3dSmrg
1385c0a68be4Smrg /* Notice GOTO expressions eliminated while constructing the CFG.
1386c0a68be4Smrg It's hard to distinguish such expression, but goto_locus should
1387c0a68be4Smrg not be any of already seen location. */
1388c0a68be4Smrg location_t loc;
13891debfc3dSmrg if (single_succ_p (bb)
1390c0a68be4Smrg && (loc = single_succ_edge (bb)->goto_locus)
1391c0a68be4Smrg && !RESERVED_LOCATION_P (loc)
1392c0a68be4Smrg && !seen_locations.contains (loc))
13931debfc3dSmrg {
1394c0a68be4Smrg expanded_location curr_location = expand_location (loc);
1395c0a68be4Smrg output_location (&streamed_locations, curr_location.file,
1396*8feb0f0bSmrg MAX (1, curr_location.line), &offset, bb);
13971debfc3dSmrg }
13981debfc3dSmrg
13991debfc3dSmrg if (offset)
14001debfc3dSmrg {
14011debfc3dSmrg /* A file of NULL indicates the end of run. */
14021debfc3dSmrg gcov_write_unsigned (0);
14031debfc3dSmrg gcov_write_string (NULL);
14041debfc3dSmrg gcov_write_length (offset);
14051debfc3dSmrg }
14061debfc3dSmrg }
14071debfc3dSmrg }
14081debfc3dSmrg
14091debfc3dSmrg if (flag_profile_values)
14101debfc3dSmrg gimple_find_values_to_profile (&values);
14111debfc3dSmrg
14121debfc3dSmrg if (flag_branch_probabilities)
14131debfc3dSmrg {
14141debfc3dSmrg compute_branch_probabilities (cfg_checksum, lineno_checksum);
14151debfc3dSmrg if (flag_profile_values)
14161debfc3dSmrg compute_value_histograms (values, cfg_checksum, lineno_checksum);
14171debfc3dSmrg }
14181debfc3dSmrg
14191debfc3dSmrg remove_fake_edges ();
14201debfc3dSmrg
14211debfc3dSmrg /* For each edge not on the spanning tree, add counting code. */
14221debfc3dSmrg if (profile_arc_flag
14231debfc3dSmrg && coverage_counter_alloc (GCOV_COUNTER_ARCS, num_instrumented))
14241debfc3dSmrg {
14251debfc3dSmrg unsigned n_instrumented;
14261debfc3dSmrg
14271debfc3dSmrg gimple_init_gcov_profiler ();
14281debfc3dSmrg
14291debfc3dSmrg n_instrumented = instrument_edges (el);
14301debfc3dSmrg
14311debfc3dSmrg gcc_assert (n_instrumented == num_instrumented);
14321debfc3dSmrg
14331debfc3dSmrg if (flag_profile_values)
14341debfc3dSmrg instrument_values (values);
14351debfc3dSmrg
14361debfc3dSmrg /* Commit changes done by instrumentation. */
14371debfc3dSmrg gsi_commit_edge_inserts ();
14381debfc3dSmrg }
14391debfc3dSmrg
14401debfc3dSmrg free_aux_for_edges ();
14411debfc3dSmrg
14421debfc3dSmrg values.release ();
14431debfc3dSmrg free_edge_list (el);
14441debfc3dSmrg coverage_end_function (lineno_checksum, cfg_checksum);
1445c0a68be4Smrg if (flag_branch_probabilities
1446c0a68be4Smrg && (profile_status_for_fn (cfun) == PROFILE_READ))
14471debfc3dSmrg {
1448*8feb0f0bSmrg class loop *loop;
14491debfc3dSmrg if (dump_file && (dump_flags & TDF_DETAILS))
14501debfc3dSmrg report_predictor_hitrates ();
14511debfc3dSmrg
14521debfc3dSmrg /* At this moment we have precise loop iteration count estimates.
14531debfc3dSmrg Record them to loop structure before the profile gets out of date. */
14541debfc3dSmrg FOR_EACH_LOOP (loop, 0)
1455*8feb0f0bSmrg if (loop->header->count > 0 && loop->header->count.reliable_p ())
14561debfc3dSmrg {
14571debfc3dSmrg gcov_type nit = expected_loop_iterations_unbounded (loop);
14581debfc3dSmrg widest_int bound = gcov_type_to_wide_int (nit);
14591debfc3dSmrg loop->any_estimate = false;
14601debfc3dSmrg record_niter_bound (loop, bound, true, false);
14611debfc3dSmrg }
14621debfc3dSmrg compute_function_frequency ();
14631debfc3dSmrg }
14641debfc3dSmrg }
14651debfc3dSmrg
14661debfc3dSmrg /* Union find algorithm implementation for the basic blocks using
14671debfc3dSmrg aux fields. */
14681debfc3dSmrg
14691debfc3dSmrg static basic_block
find_group(basic_block bb)14701debfc3dSmrg find_group (basic_block bb)
14711debfc3dSmrg {
14721debfc3dSmrg basic_block group = bb, bb1;
14731debfc3dSmrg
14741debfc3dSmrg while ((basic_block) group->aux != group)
14751debfc3dSmrg group = (basic_block) group->aux;
14761debfc3dSmrg
14771debfc3dSmrg /* Compress path. */
14781debfc3dSmrg while ((basic_block) bb->aux != group)
14791debfc3dSmrg {
14801debfc3dSmrg bb1 = (basic_block) bb->aux;
14811debfc3dSmrg bb->aux = (void *) group;
14821debfc3dSmrg bb = bb1;
14831debfc3dSmrg }
14841debfc3dSmrg return group;
14851debfc3dSmrg }
14861debfc3dSmrg
14871debfc3dSmrg static void
union_groups(basic_block bb1,basic_block bb2)14881debfc3dSmrg union_groups (basic_block bb1, basic_block bb2)
14891debfc3dSmrg {
14901debfc3dSmrg basic_block bb1g = find_group (bb1);
14911debfc3dSmrg basic_block bb2g = find_group (bb2);
14921debfc3dSmrg
14931debfc3dSmrg /* ??? I don't have a place for the rank field. OK. Lets go w/o it,
14941debfc3dSmrg this code is unlikely going to be performance problem anyway. */
14951debfc3dSmrg gcc_assert (bb1g != bb2g);
14961debfc3dSmrg
14971debfc3dSmrg bb1g->aux = bb2g;
14981debfc3dSmrg }
14991debfc3dSmrg
15001debfc3dSmrg /* This function searches all of the edges in the program flow graph, and puts
15011debfc3dSmrg as many bad edges as possible onto the spanning tree. Bad edges include
15021debfc3dSmrg abnormals edges, which can't be instrumented at the moment. Since it is
15031debfc3dSmrg possible for fake edges to form a cycle, we will have to develop some
15041debfc3dSmrg better way in the future. Also put critical edges to the tree, since they
15051debfc3dSmrg are more expensive to instrument. */
15061debfc3dSmrg
15071debfc3dSmrg static void
find_spanning_tree(struct edge_list * el)15081debfc3dSmrg find_spanning_tree (struct edge_list *el)
15091debfc3dSmrg {
15101debfc3dSmrg int i;
15111debfc3dSmrg int num_edges = NUM_EDGES (el);
15121debfc3dSmrg basic_block bb;
15131debfc3dSmrg
15141debfc3dSmrg /* We use aux field for standard union-find algorithm. */
15151debfc3dSmrg FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun), NULL, next_bb)
15161debfc3dSmrg bb->aux = bb;
15171debfc3dSmrg
15181debfc3dSmrg /* Add fake edge exit to entry we can't instrument. */
15191debfc3dSmrg union_groups (EXIT_BLOCK_PTR_FOR_FN (cfun), ENTRY_BLOCK_PTR_FOR_FN (cfun));
15201debfc3dSmrg
15211debfc3dSmrg /* First add all abnormal edges to the tree unless they form a cycle. Also
15221debfc3dSmrg add all edges to the exit block to avoid inserting profiling code behind
15231debfc3dSmrg setting return value from function. */
15241debfc3dSmrg for (i = 0; i < num_edges; i++)
15251debfc3dSmrg {
15261debfc3dSmrg edge e = INDEX_EDGE (el, i);
15271debfc3dSmrg if (((e->flags & (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL | EDGE_FAKE))
15281debfc3dSmrg || e->dest == EXIT_BLOCK_PTR_FOR_FN (cfun))
15291debfc3dSmrg && !EDGE_INFO (e)->ignore
15301debfc3dSmrg && (find_group (e->src) != find_group (e->dest)))
15311debfc3dSmrg {
15321debfc3dSmrg if (dump_file)
15331debfc3dSmrg fprintf (dump_file, "Abnormal edge %d to %d put to tree\n",
15341debfc3dSmrg e->src->index, e->dest->index);
15351debfc3dSmrg EDGE_INFO (e)->on_tree = 1;
15361debfc3dSmrg union_groups (e->src, e->dest);
15371debfc3dSmrg }
15381debfc3dSmrg }
15391debfc3dSmrg
1540a2dc1f3fSmrg /* And now the rest. Edge list is sorted according to frequencies and
1541a2dc1f3fSmrg thus we will produce minimal spanning tree. */
15421debfc3dSmrg for (i = 0; i < num_edges; i++)
15431debfc3dSmrg {
15441debfc3dSmrg edge e = INDEX_EDGE (el, i);
15451debfc3dSmrg if (!EDGE_INFO (e)->ignore
15461debfc3dSmrg && find_group (e->src) != find_group (e->dest))
15471debfc3dSmrg {
15481debfc3dSmrg if (dump_file)
15491debfc3dSmrg fprintf (dump_file, "Normal edge %d to %d put to tree\n",
15501debfc3dSmrg e->src->index, e->dest->index);
15511debfc3dSmrg EDGE_INFO (e)->on_tree = 1;
15521debfc3dSmrg union_groups (e->src, e->dest);
15531debfc3dSmrg }
15541debfc3dSmrg }
15551debfc3dSmrg
15561debfc3dSmrg clear_aux_for_blocks ();
15571debfc3dSmrg }
15581debfc3dSmrg
15591debfc3dSmrg /* Perform file-level initialization for branch-prob processing. */
15601debfc3dSmrg
15611debfc3dSmrg void
init_branch_prob(void)15621debfc3dSmrg init_branch_prob (void)
15631debfc3dSmrg {
15641debfc3dSmrg int i;
15651debfc3dSmrg
15661debfc3dSmrg total_num_blocks = 0;
15671debfc3dSmrg total_num_edges = 0;
15681debfc3dSmrg total_num_edges_ignored = 0;
15691debfc3dSmrg total_num_edges_instrumented = 0;
15701debfc3dSmrg total_num_blocks_created = 0;
15711debfc3dSmrg total_num_passes = 0;
15721debfc3dSmrg total_num_times_called = 0;
15731debfc3dSmrg total_num_branches = 0;
15741debfc3dSmrg for (i = 0; i < 20; i++)
15751debfc3dSmrg total_hist_br_prob[i] = 0;
15761debfc3dSmrg }
15771debfc3dSmrg
15781debfc3dSmrg /* Performs file-level cleanup after branch-prob processing
15791debfc3dSmrg is completed. */
15801debfc3dSmrg
15811debfc3dSmrg void
end_branch_prob(void)15821debfc3dSmrg end_branch_prob (void)
15831debfc3dSmrg {
15841debfc3dSmrg if (dump_file)
15851debfc3dSmrg {
15861debfc3dSmrg fprintf (dump_file, "\n");
15871debfc3dSmrg fprintf (dump_file, "Total number of blocks: %d\n",
15881debfc3dSmrg total_num_blocks);
15891debfc3dSmrg fprintf (dump_file, "Total number of edges: %d\n", total_num_edges);
15901debfc3dSmrg fprintf (dump_file, "Total number of ignored edges: %d\n",
15911debfc3dSmrg total_num_edges_ignored);
15921debfc3dSmrg fprintf (dump_file, "Total number of instrumented edges: %d\n",
15931debfc3dSmrg total_num_edges_instrumented);
15941debfc3dSmrg fprintf (dump_file, "Total number of blocks created: %d\n",
15951debfc3dSmrg total_num_blocks_created);
15961debfc3dSmrg fprintf (dump_file, "Total number of graph solution passes: %d\n",
15971debfc3dSmrg total_num_passes);
15981debfc3dSmrg if (total_num_times_called != 0)
15991debfc3dSmrg fprintf (dump_file, "Average number of graph solution passes: %d\n",
16001debfc3dSmrg (total_num_passes + (total_num_times_called >> 1))
16011debfc3dSmrg / total_num_times_called);
16021debfc3dSmrg fprintf (dump_file, "Total number of branches: %d\n",
16031debfc3dSmrg total_num_branches);
16041debfc3dSmrg if (total_num_branches)
16051debfc3dSmrg {
16061debfc3dSmrg int i;
16071debfc3dSmrg
16081debfc3dSmrg for (i = 0; i < 10; i++)
16091debfc3dSmrg fprintf (dump_file, "%d%% branches in range %d-%d%%\n",
16101debfc3dSmrg (total_hist_br_prob[i] + total_hist_br_prob[19-i]) * 100
16111debfc3dSmrg / total_num_branches, 5*i, 5*i+5);
16121debfc3dSmrg }
16131debfc3dSmrg }
16141debfc3dSmrg }
1615