123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789 |
- /* Basic IPA optimizations based on profile.
- Copyright (C) 2003-2015 Free Software Foundation, Inc.
- This file is part of GCC.
- GCC is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free
- Software Foundation; either version 3, or (at your option) any later
- version.
- GCC is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- for more details.
- You should have received a copy of the GNU General Public License
- along with GCC; see the file COPYING3. If not see
- <http://www.gnu.org/licenses/>. */
- /* ipa-profile pass implements the following analysis propagating profille
- inter-procedurally.
- - Count histogram construction. This is a histogram analyzing how much
- time is spent executing statements with a given execution count read
- from profile feedback. This histogram is complete only with LTO,
- otherwise it contains information only about the current unit.
- Similar histogram is also estimated by coverage runtime. This histogram
- is not dependent on LTO, but it suffers from various defects; first
- gcov runtime is not weighting individual basic block by estimated execution
- time and second the merging of multiple runs makes assumption that the
- histogram distribution did not change. Consequentely histogram constructed
- here may be more precise.
- The information is used to set hot/cold thresholds.
- - Next speculative indirect call resolution is performed: the local
- profile pass assigns profile-id to each function and provide us with a
- histogram specifying the most common target. We look up the callgraph
- node corresponding to the target and produce a speculative call.
- This call may or may not survive through IPA optimization based on decision
- of inliner.
- - Finally we propagate the following flags: unlikely executed, executed
- once, executed at startup and executed at exit. These flags are used to
- control code size/performance threshold and and code placement (by producing
- .text.unlikely/.text.hot/.text.startup/.text.exit subsections). */
- #include "config.h"
- #include "system.h"
- #include "coretypes.h"
- #include "tm.h"
- #include "hash-set.h"
- #include "machmode.h"
- #include "vec.h"
- #include "double-int.h"
- #include "input.h"
- #include "alias.h"
- #include "symtab.h"
- #include "wide-int.h"
- #include "inchash.h"
- #include "tree.h"
- #include "fold-const.h"
- #include "predict.h"
- #include "dominance.h"
- #include "cfg.h"
- #include "basic-block.h"
- #include "hash-map.h"
- #include "is-a.h"
- #include "plugin-api.h"
- #include "hard-reg-set.h"
- #include "input.h"
- #include "function.h"
- #include "ipa-ref.h"
- #include "cgraph.h"
- #include "tree-pass.h"
- #include "tree-ssa-alias.h"
- #include "internal-fn.h"
- #include "gimple-expr.h"
- #include "gimple.h"
- #include "gimple-iterator.h"
- #include "flags.h"
- #include "target.h"
- #include "tree-iterator.h"
- #include "ipa-utils.h"
- #include "profile.h"
- #include "params.h"
- #include "value-prof.h"
- #include "alloc-pool.h"
- #include "tree-inline.h"
- #include "lto-streamer.h"
- #include "data-streamer.h"
- #include "symbol-summary.h"
- #include "ipa-prop.h"
- #include "ipa-inline.h"
- /* Entry in the histogram. */
- struct histogram_entry
- {
- gcov_type count;
- int time;
- int size;
- };
- /* Histogram of profile values.
- The histogram is represented as an ordered vector of entries allocated via
- histogram_pool. During construction a separate hashtable is kept to lookup
- duplicate entries. */
- vec<histogram_entry *> histogram;
- static alloc_pool histogram_pool;
- /* Hashtable support for storing SSA names hashed by their SSA_NAME_VAR. */
- struct histogram_hash : typed_noop_remove <histogram_entry>
- {
- typedef histogram_entry value_type;
- typedef histogram_entry compare_type;
- static inline hashval_t hash (const value_type *);
- static inline int equal (const value_type *, const compare_type *);
- };
- inline hashval_t
- histogram_hash::hash (const histogram_entry *val)
- {
- return val->count;
- }
- inline int
- histogram_hash::equal (const histogram_entry *val, const histogram_entry *val2)
- {
- return val->count == val2->count;
- }
- /* Account TIME and SIZE executed COUNT times into HISTOGRAM.
- HASHTABLE is the on-side hash kept to avoid duplicates. */
- static void
- account_time_size (hash_table<histogram_hash> *hashtable,
- vec<histogram_entry *> &histogram,
- gcov_type count, int time, int size)
- {
- histogram_entry key = {count, 0, 0};
- histogram_entry **val = hashtable->find_slot (&key, INSERT);
- if (!*val)
- {
- *val = (histogram_entry *) pool_alloc (histogram_pool);
- **val = key;
- histogram.safe_push (*val);
- }
- (*val)->time += time;
- (*val)->size += size;
- }
- int
- cmp_counts (const void *v1, const void *v2)
- {
- const histogram_entry *h1 = *(const histogram_entry * const *)v1;
- const histogram_entry *h2 = *(const histogram_entry * const *)v2;
- if (h1->count < h2->count)
- return 1;
- if (h1->count > h2->count)
- return -1;
- return 0;
- }
- /* Dump HISTOGRAM to FILE. */
- static void
- dump_histogram (FILE *file, vec<histogram_entry *> histogram)
- {
- unsigned int i;
- gcov_type overall_time = 0, cumulated_time = 0, cumulated_size = 0, overall_size = 0;
-
- fprintf (dump_file, "Histogram:\n");
- for (i = 0; i < histogram.length (); i++)
- {
- overall_time += histogram[i]->count * histogram[i]->time;
- overall_size += histogram[i]->size;
- }
- if (!overall_time)
- overall_time = 1;
- if (!overall_size)
- overall_size = 1;
- for (i = 0; i < histogram.length (); i++)
- {
- cumulated_time += histogram[i]->count * histogram[i]->time;
- cumulated_size += histogram[i]->size;
- fprintf (file, " %"PRId64": time:%i (%2.2f) size:%i (%2.2f)\n",
- (int64_t) histogram[i]->count,
- histogram[i]->time,
- cumulated_time * 100.0 / overall_time,
- histogram[i]->size,
- cumulated_size * 100.0 / overall_size);
- }
- }
- /* Collect histogram from CFG profiles. */
- static void
- ipa_profile_generate_summary (void)
- {
- struct cgraph_node *node;
- gimple_stmt_iterator gsi;
- basic_block bb;
- hash_table<histogram_hash> hashtable (10);
- histogram_pool = create_alloc_pool ("IPA histogram", sizeof (struct histogram_entry),
- 10);
-
- FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
- FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (node->decl))
- {
- int time = 0;
- int size = 0;
- for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
- {
- gimple stmt = gsi_stmt (gsi);
- if (gimple_code (stmt) == GIMPLE_CALL
- && !gimple_call_fndecl (stmt))
- {
- histogram_value h;
- h = gimple_histogram_value_of_type
- (DECL_STRUCT_FUNCTION (node->decl),
- stmt, HIST_TYPE_INDIR_CALL);
- /* No need to do sanity check: gimple_ic_transform already
- takes away bad histograms. */
- if (h)
- {
- /* counter 0 is target, counter 1 is number of execution we called target,
- counter 2 is total number of executions. */
- if (h->hvalue.counters[2])
- {
- struct cgraph_edge * e = node->get_edge (stmt);
- if (e && !e->indirect_unknown_callee)
- continue;
- e->indirect_info->common_target_id
- = h->hvalue.counters [0];
- e->indirect_info->common_target_probability
- = GCOV_COMPUTE_SCALE (h->hvalue.counters [1], h->hvalue.counters [2]);
- if (e->indirect_info->common_target_probability > REG_BR_PROB_BASE)
- {
- if (dump_file)
- fprintf (dump_file, "Probability capped to 1\n");
- e->indirect_info->common_target_probability = REG_BR_PROB_BASE;
- }
- }
- gimple_remove_histogram_value (DECL_STRUCT_FUNCTION (node->decl),
- stmt, h);
- }
- }
- time += estimate_num_insns (stmt, &eni_time_weights);
- size += estimate_num_insns (stmt, &eni_size_weights);
- }
- account_time_size (&hashtable, histogram, bb->count, time, size);
- }
- histogram.qsort (cmp_counts);
- }
- /* Serialize the ipa info for lto. */
- static void
- ipa_profile_write_summary (void)
- {
- struct lto_simple_output_block *ob
- = lto_create_simple_output_block (LTO_section_ipa_profile);
- unsigned int i;
- streamer_write_uhwi_stream (ob->main_stream, histogram.length ());
- for (i = 0; i < histogram.length (); i++)
- {
- streamer_write_gcov_count_stream (ob->main_stream, histogram[i]->count);
- streamer_write_uhwi_stream (ob->main_stream, histogram[i]->time);
- streamer_write_uhwi_stream (ob->main_stream, histogram[i]->size);
- }
- lto_destroy_simple_output_block (ob);
- }
- /* Deserialize the ipa info for lto. */
- static void
- ipa_profile_read_summary (void)
- {
- struct lto_file_decl_data ** file_data_vec
- = lto_get_file_decl_data ();
- struct lto_file_decl_data * file_data;
- int j = 0;
- hash_table<histogram_hash> hashtable (10);
- histogram_pool = create_alloc_pool ("IPA histogram", sizeof (struct histogram_entry),
- 10);
- while ((file_data = file_data_vec[j++]))
- {
- const char *data;
- size_t len;
- struct lto_input_block *ib
- = lto_create_simple_input_block (file_data,
- LTO_section_ipa_profile,
- &data, &len);
- if (ib)
- {
- unsigned int num = streamer_read_uhwi (ib);
- unsigned int n;
- for (n = 0; n < num; n++)
- {
- gcov_type count = streamer_read_gcov_count (ib);
- int time = streamer_read_uhwi (ib);
- int size = streamer_read_uhwi (ib);
- account_time_size (&hashtable, histogram,
- count, time, size);
- }
- lto_destroy_simple_input_block (file_data,
- LTO_section_ipa_profile,
- ib, data, len);
- }
- }
- histogram.qsort (cmp_counts);
- }
- /* Data used by ipa_propagate_frequency. */
- struct ipa_propagate_frequency_data
- {
- cgraph_node *function_symbol;
- bool maybe_unlikely_executed;
- bool maybe_executed_once;
- bool only_called_at_startup;
- bool only_called_at_exit;
- };
- /* Worker for ipa_propagate_frequency_1. */
- static bool
- ipa_propagate_frequency_1 (struct cgraph_node *node, void *data)
- {
- struct ipa_propagate_frequency_data *d;
- struct cgraph_edge *edge;
- d = (struct ipa_propagate_frequency_data *)data;
- for (edge = node->callers;
- edge && (d->maybe_unlikely_executed || d->maybe_executed_once
- || d->only_called_at_startup || d->only_called_at_exit);
- edge = edge->next_caller)
- {
- if (edge->caller != d->function_symbol)
- {
- d->only_called_at_startup &= edge->caller->only_called_at_startup;
- /* It makes sense to put main() together with the static constructors.
- It will be executed for sure, but rest of functions called from
- main are definitely not at startup only. */
- if (MAIN_NAME_P (DECL_NAME (edge->caller->decl)))
- d->only_called_at_startup = 0;
- d->only_called_at_exit &= edge->caller->only_called_at_exit;
- }
- /* When profile feedback is available, do not try to propagate too hard;
- counts are already good guide on function frequencies and roundoff
- errors can make us to push function into unlikely section even when
- it is executed by the train run. Transfer the function only if all
- callers are unlikely executed. */
- if (profile_info
- && opt_for_fn (d->function_symbol->decl, flag_branch_probabilities)
- /* Thunks are not profiled. This is more or less implementation
- bug. */
- && !d->function_symbol->thunk.thunk_p
- && (edge->caller->frequency != NODE_FREQUENCY_UNLIKELY_EXECUTED
- || (edge->caller->global.inlined_to
- && edge->caller->global.inlined_to->frequency
- != NODE_FREQUENCY_UNLIKELY_EXECUTED)))
- d->maybe_unlikely_executed = false;
- if (!edge->frequency)
- continue;
- switch (edge->caller->frequency)
- {
- case NODE_FREQUENCY_UNLIKELY_EXECUTED:
- break;
- case NODE_FREQUENCY_EXECUTED_ONCE:
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, " Called by %s that is executed once\n",
- edge->caller->name ());
- d->maybe_unlikely_executed = false;
- if (inline_edge_summary (edge)->loop_depth)
- {
- d->maybe_executed_once = false;
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, " Called in loop\n");
- }
- break;
- case NODE_FREQUENCY_HOT:
- case NODE_FREQUENCY_NORMAL:
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, " Called by %s that is normal or hot\n",
- edge->caller->name ());
- d->maybe_unlikely_executed = false;
- d->maybe_executed_once = false;
- break;
- }
- }
- return edge != NULL;
- }
- /* Return ture if NODE contains hot calls. */
- bool
- contains_hot_call_p (struct cgraph_node *node)
- {
- struct cgraph_edge *e;
- for (e = node->callees; e; e = e->next_callee)
- if (e->maybe_hot_p ())
- return true;
- else if (!e->inline_failed
- && contains_hot_call_p (e->callee))
- return true;
- for (e = node->indirect_calls; e; e = e->next_callee)
- if (e->maybe_hot_p ())
- return true;
- return false;
- }
- /* See if the frequency of NODE can be updated based on frequencies of its
- callers. */
- bool
- ipa_propagate_frequency (struct cgraph_node *node)
- {
- struct ipa_propagate_frequency_data d = {node, true, true, true, true};
- bool changed = false;
- /* We can not propagate anything useful about externally visible functions
- nor about virtuals. */
- if (!node->local.local
- || node->alias
- || (opt_for_fn (node->decl, flag_devirtualize)
- && DECL_VIRTUAL_P (node->decl)))
- return false;
- gcc_assert (node->analyzed);
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, "Processing frequency %s\n", node->name ());
- node->call_for_symbol_and_aliases (ipa_propagate_frequency_1, &d,
- true);
- if ((d.only_called_at_startup && !d.only_called_at_exit)
- && !node->only_called_at_startup)
- {
- node->only_called_at_startup = true;
- if (dump_file)
- fprintf (dump_file, "Node %s promoted to only called at startup.\n",
- node->name ());
- changed = true;
- }
- if ((d.only_called_at_exit && !d.only_called_at_startup)
- && !node->only_called_at_exit)
- {
- node->only_called_at_exit = true;
- if (dump_file)
- fprintf (dump_file, "Node %s promoted to only called at exit.\n",
- node->name ());
- changed = true;
- }
- /* With profile we can decide on hot/normal based on count. */
- if (node->count)
- {
- bool hot = false;
- if (node->count >= get_hot_bb_threshold ())
- hot = true;
- if (!hot)
- hot |= contains_hot_call_p (node);
- if (hot)
- {
- if (node->frequency != NODE_FREQUENCY_HOT)
- {
- if (dump_file)
- fprintf (dump_file, "Node %s promoted to hot.\n",
- node->name ());
- node->frequency = NODE_FREQUENCY_HOT;
- return true;
- }
- return false;
- }
- else if (node->frequency == NODE_FREQUENCY_HOT)
- {
- if (dump_file)
- fprintf (dump_file, "Node %s reduced to normal.\n",
- node->name ());
- node->frequency = NODE_FREQUENCY_NORMAL;
- changed = true;
- }
- }
- /* These come either from profile or user hints; never update them. */
- if (node->frequency == NODE_FREQUENCY_HOT
- || node->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED)
- return changed;
- if (d.maybe_unlikely_executed)
- {
- node->frequency = NODE_FREQUENCY_UNLIKELY_EXECUTED;
- if (dump_file)
- fprintf (dump_file, "Node %s promoted to unlikely executed.\n",
- node->name ());
- changed = true;
- }
- else if (d.maybe_executed_once && node->frequency != NODE_FREQUENCY_EXECUTED_ONCE)
- {
- node->frequency = NODE_FREQUENCY_EXECUTED_ONCE;
- if (dump_file)
- fprintf (dump_file, "Node %s promoted to executed once.\n",
- node->name ());
- changed = true;
- }
- return changed;
- }
- /* Simple ipa profile pass propagating frequencies across the callgraph. */
- static unsigned int
- ipa_profile (void)
- {
- struct cgraph_node **order;
- struct cgraph_edge *e;
- int order_pos;
- bool something_changed = false;
- int i;
- gcov_type overall_time = 0, cutoff = 0, cumulated = 0, overall_size = 0;
- struct cgraph_node *n,*n2;
- int nindirect = 0, ncommon = 0, nunknown = 0, nuseless = 0, nconverted = 0;
- bool node_map_initialized = false;
- if (dump_file)
- dump_histogram (dump_file, histogram);
- for (i = 0; i < (int)histogram.length (); i++)
- {
- overall_time += histogram[i]->count * histogram[i]->time;
- overall_size += histogram[i]->size;
- }
- if (overall_time)
- {
- gcov_type threshold;
- gcc_assert (overall_size);
- if (dump_file)
- {
- gcov_type min, cumulated_time = 0, cumulated_size = 0;
- fprintf (dump_file, "Overall time: %"PRId64"\n",
- (int64_t)overall_time);
- min = get_hot_bb_threshold ();
- for (i = 0; i < (int)histogram.length () && histogram[i]->count >= min;
- i++)
- {
- cumulated_time += histogram[i]->count * histogram[i]->time;
- cumulated_size += histogram[i]->size;
- }
- fprintf (dump_file, "GCOV min count: %"PRId64
- " Time:%3.2f%% Size:%3.2f%%\n",
- (int64_t)min,
- cumulated_time * 100.0 / overall_time,
- cumulated_size * 100.0 / overall_size);
- }
- cutoff = (overall_time * PARAM_VALUE (HOT_BB_COUNT_WS_PERMILLE) + 500) / 1000;
- threshold = 0;
- for (i = 0; cumulated < cutoff; i++)
- {
- cumulated += histogram[i]->count * histogram[i]->time;
- threshold = histogram[i]->count;
- }
- if (!threshold)
- threshold = 1;
- if (dump_file)
- {
- gcov_type cumulated_time = 0, cumulated_size = 0;
- for (i = 0;
- i < (int)histogram.length () && histogram[i]->count >= threshold;
- i++)
- {
- cumulated_time += histogram[i]->count * histogram[i]->time;
- cumulated_size += histogram[i]->size;
- }
- fprintf (dump_file, "Determined min count: %"PRId64
- " Time:%3.2f%% Size:%3.2f%%\n",
- (int64_t)threshold,
- cumulated_time * 100.0 / overall_time,
- cumulated_size * 100.0 / overall_size);
- }
- if (threshold > get_hot_bb_threshold ()
- || in_lto_p)
- {
- if (dump_file)
- fprintf (dump_file, "Threshold updated.\n");
- set_hot_bb_threshold (threshold);
- }
- }
- histogram.release ();
- free_alloc_pool (histogram_pool);
- /* Produce speculative calls: we saved common traget from porfiling into
- e->common_target_id. Now, at link time, we can look up corresponding
- function node and produce speculative call. */
- FOR_EACH_DEFINED_FUNCTION (n)
- {
- bool update = false;
- if (!opt_for_fn (n->decl, flag_ipa_profile))
- continue;
- for (e = n->indirect_calls; e; e = e->next_callee)
- {
- if (n->count)
- nindirect++;
- if (e->indirect_info->common_target_id)
- {
- if (!node_map_initialized)
- init_node_map (false);
- node_map_initialized = true;
- ncommon++;
- n2 = find_func_by_profile_id (e->indirect_info->common_target_id);
- if (n2)
- {
- if (dump_file)
- {
- fprintf (dump_file, "Indirect call -> direct call from"
- " other module %s/%i => %s/%i, prob %3.2f\n",
- xstrdup_for_dump (n->name ()), n->order,
- xstrdup_for_dump (n2->name ()), n2->order,
- e->indirect_info->common_target_probability
- / (float)REG_BR_PROB_BASE);
- }
- if (e->indirect_info->common_target_probability
- < REG_BR_PROB_BASE / 2)
- {
- nuseless++;
- if (dump_file)
- fprintf (dump_file,
- "Not speculating: probability is too low.\n");
- }
- else if (!e->maybe_hot_p ())
- {
- nuseless++;
- if (dump_file)
- fprintf (dump_file,
- "Not speculating: call is cold.\n");
- }
- else if (n2->get_availability () <= AVAIL_INTERPOSABLE
- && n2->can_be_discarded_p ())
- {
- nuseless++;
- if (dump_file)
- fprintf (dump_file,
- "Not speculating: target is overwritable "
- "and can be discarded.\n");
- }
- else
- {
- /* Target may be overwritable, but profile says that
- control flow goes to this particular implementation
- of N2. Speculate on the local alias to allow inlining.
- */
- if (!n2->can_be_discarded_p ())
- {
- cgraph_node *alias;
- alias = dyn_cast<cgraph_node *> (n2->noninterposable_alias ());
- if (alias)
- n2 = alias;
- }
- nconverted++;
- e->make_speculative
- (n2,
- apply_scale (e->count,
- e->indirect_info->common_target_probability),
- apply_scale (e->frequency,
- e->indirect_info->common_target_probability));
- update = true;
- }
- }
- else
- {
- if (dump_file)
- fprintf (dump_file, "Function with profile-id %i not found.\n",
- e->indirect_info->common_target_id);
- nunknown++;
- }
- }
- }
- if (update)
- inline_update_overall_summary (n);
- }
- if (node_map_initialized)
- del_node_map ();
- if (dump_file && nindirect)
- fprintf (dump_file,
- "%i indirect calls trained.\n"
- "%i (%3.2f%%) have common target.\n"
- "%i (%3.2f%%) targets was not found.\n"
- "%i (%3.2f%%) speculations seems useless.\n"
- "%i (%3.2f%%) speculations produced.\n",
- nindirect,
- ncommon, ncommon * 100.0 / nindirect,
- nunknown, nunknown * 100.0 / nindirect,
- nuseless, nuseless * 100.0 / nindirect,
- nconverted, nconverted * 100.0 / nindirect);
- order = XCNEWVEC (struct cgraph_node *, symtab->cgraph_count);
- order_pos = ipa_reverse_postorder (order);
- for (i = order_pos - 1; i >= 0; i--)
- {
- if (order[i]->local.local
- && opt_for_fn (order[i]->decl, flag_ipa_profile)
- && ipa_propagate_frequency (order[i]))
- {
- for (e = order[i]->callees; e; e = e->next_callee)
- if (e->callee->local.local && !e->callee->aux)
- {
- something_changed = true;
- e->callee->aux = (void *)1;
- }
- }
- order[i]->aux = NULL;
- }
- while (something_changed)
- {
- something_changed = false;
- for (i = order_pos - 1; i >= 0; i--)
- {
- if (order[i]->aux
- && opt_for_fn (order[i]->decl, flag_ipa_profile)
- && ipa_propagate_frequency (order[i]))
- {
- for (e = order[i]->callees; e; e = e->next_callee)
- if (e->callee->local.local && !e->callee->aux)
- {
- something_changed = true;
- e->callee->aux = (void *)1;
- }
- }
- order[i]->aux = NULL;
- }
- }
- free (order);
- return 0;
- }
- namespace {
- const pass_data pass_data_ipa_profile =
- {
- IPA_PASS, /* type */
- "profile_estimate", /* name */
- OPTGROUP_NONE, /* optinfo_flags */
- TV_IPA_PROFILE, /* tv_id */
- 0, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- 0, /* todo_flags_finish */
- };
- class pass_ipa_profile : public ipa_opt_pass_d
- {
- public:
- pass_ipa_profile (gcc::context *ctxt)
- : ipa_opt_pass_d (pass_data_ipa_profile, ctxt,
- ipa_profile_generate_summary, /* generate_summary */
- ipa_profile_write_summary, /* write_summary */
- ipa_profile_read_summary, /* read_summary */
- NULL, /* write_optimization_summary */
- NULL, /* read_optimization_summary */
- NULL, /* stmt_fixup */
- 0, /* function_transform_todo_flags_start */
- NULL, /* function_transform */
- NULL) /* variable_transform */
- {}
- /* opt_pass methods: */
- virtual bool gate (function *) { return flag_ipa_profile || in_lto_p; }
- virtual unsigned int execute (function *) { return ipa_profile (); }
- }; // class pass_ipa_profile
- } // anon namespace
- ipa_opt_pass_d *
- make_pass_ipa_profile (gcc::context *ctxt)
- {
- return new pass_ipa_profile (ctxt);
- }
|