#include "config.h"
#include "system.h"
#include "coretypes.h"
-#include "hash-set.h"
-#include "machmode.h"
-#include "vec.h"
-#include "hash-map.h"
-#include "double-int.h"
-#include "input.h"
#include "alias.h"
#include "symtab.h"
#include "options.h"
-#include "wide-int.h"
-#include "inchash.h"
#include "tree.h"
#include "fold-const.h"
#include "gimple-fold.h"
#include "target.h"
#include "predict.h"
#include "basic-block.h"
-#include "is-a.h"
-#include "plugin-api.h"
#include "tm.h"
#include "hard-reg-set.h"
-#include "input.h"
#include "function.h"
-#include "ipa-ref.h"
#include "cgraph.h"
#include "alloc-pool.h"
#include "symbol-summary.h"
/* Allocation pools for values and their sources in ipa-cp. */
-alloc_pool ipcp_cst_values_pool;
-alloc_pool ipcp_poly_ctx_values_pool;
-alloc_pool ipcp_sources_pool;
-alloc_pool ipcp_agg_lattice_pool;
+pool_allocator<ipcp_value<tree> > ipcp_cst_values_pool
+ ("IPA-CP constant values", 32);
+
+pool_allocator<ipcp_value<ipa_polymorphic_call_context> >
+ ipcp_poly_ctx_values_pool ("IPA-CP polymorphic contexts", 32);
+
+pool_allocator<ipcp_value_source<tree> > ipcp_sources_pool
+ ("IPA-CP value sources", 64);
+
+pool_allocator<ipcp_agg_lattice> ipcp_agg_lattice_pool
+ ("IPA_CP aggregate lattices", 32);
/* Maximal count found in program. */
struct cgraph_edge *cs;
for (cs = node->callers; cs; cs = cs->next_caller)
- if (cs->caller->thunk.thunk_p)
- cs->caller->call_for_symbol_thunks_and_aliases (gather_caller_stats,
- stats, false);
- else
+ if (!cs->caller->thunk.thunk_p)
{
stats->count_sum += cs->count;
stats->freq_sum += cs->frequency;
return ret;
}
+/* Worker of call_for_symbol_thunks_and_aliases, increment the integer DATA
+ points to by the number of callers to NODE. */
+
+static bool
+count_callers (cgraph_node *node, void *data)
+{
+ int *caller_count = (int *) data;
+
+ for (cgraph_edge *cs = node->callers; cs; cs = cs->next_caller)
+ /* Local thunks can be handled transparently, but if the thunk can not
+ be optimized out, count it as a real use. */
+ if (!cs->caller->thunk.thunk_p || !cs->caller->local.local)
+ ++*caller_count;
+ return false;
+}
+
+/* Worker of call_for_symbol_thunks_and_aliases, it is supposed to be called on
+ the one caller of some other node. Set the caller's corresponding flag. */
+
+static bool
+set_single_call_flag (cgraph_node *node, void *)
+{
+ cgraph_edge *cs = node->callers;
+ /* Local thunks can be handled transparently, skip them. */
+ while (cs && cs->caller->thunk.thunk_p && cs->caller->local.local)
+ cs = cs->next_caller;
+ if (cs)
+ {
+ IPA_NODE_REF (cs->caller)->node_calling_single_call = true;
+ return true;
+ }
+ return false;
+}
+
/* Initialize ipcp_lattices. */
static void
int i;
gcc_checking_assert (node->has_gimple_body_p ());
- if (!cgraph_local_p (node))
+ if (cgraph_local_p (node))
+ {
+ int caller_count = 0;
+ node->call_for_symbol_thunks_and_aliases (count_callers, &caller_count,
+ true);
+ gcc_checking_assert (caller_count > 0);
+ if (caller_count == 1)
+ node->call_for_symbol_thunks_and_aliases (set_single_call_flag,
+ NULL, true);
+ }
+ else
{
/* When cloning is allowed, we can assume that externally visible
functions are not called. We will compensate this by cloning
{
ipcp_lattice<tree> *lat;
- if (!info->lattices)
+ if (!info->lattices
+ || idx >= ipa_get_param_count (info))
return NULL_TREE;
lat = ipa_get_scalar_lat (info, idx);
if (!lat->is_single_const ())
}
else
{
- if (!info->lattices)
+ if (!info->lattices
+ || srcidx >= ipa_get_param_count (info))
return ctx;
ipcp_lattice<ipa_polymorphic_call_context> *lat;
lat = ipa_get_poly_ctx_lat (info, srcidx);
{
ipcp_value_source<valtype> *src;
- src = new (pool_alloc (ipcp_sources_pool)) ipcp_value_source<valtype>;
+ src = new (ipcp_sources_pool.allocate ()) ipcp_value_source<valtype>;
src->offset = offset;
src->cs = cs;
src->val = src_val;
{
ipcp_value<tree> *val;
- val = new (pool_alloc (ipcp_cst_values_pool)) ipcp_value<tree>;
+ val = ipcp_cst_values_pool.allocate ();
memset (val, 0, sizeof (*val));
val->value = source;
return val;
{
ipcp_value<ipa_polymorphic_call_context> *val;
- val = new (pool_alloc (ipcp_poly_ctx_values_pool))
- ipcp_value<ipa_polymorphic_call_context>;
+ // TODO
+ val = ipcp_poly_ctx_values_pool.allocate ();
memset (val, 0, sizeof (*val));
val->value = source;
return val;
{
ipcp_value_source<valtype> *src = val->sources;
val->sources = src->next;
- pool_free (ipcp_sources_pool, src);
+ ipcp_sources_pool.remove ((ipcp_value_source<tree>*)src);
}
}
if (op != NOP_EXPR)
{
if (op != POINTER_PLUS_EXPR
- && op != PLUS_EXPR
- && op != MINUS_EXPR)
+ && op != PLUS_EXPR)
goto prop_fail;
tree operand = ipa_get_jf_pass_through_operand (jfunc);
if (!tree_fits_shwi_p (operand))
else
{
src_idx = ipa_get_jf_ancestor_formal_id (jfunc);
- offset = ipa_get_jf_ancestor_offset (jfunc);
+ offset = ipa_get_jf_ancestor_offset (jfunc) / BITS_PER_UNIT;;
}
src_lats = ipa_get_parm_lattices (caller_info, src_idx);
if (dest_plats->aggs_count == PARAM_VALUE (PARAM_IPA_MAX_AGG_ITEMS))
return false;
dest_plats->aggs_count++;
- new_al = (struct ipcp_agg_lattice *) pool_alloc (ipcp_agg_lattice_pool);
+ new_al = ipcp_agg_lattice_pool.allocate ();
memset (new_al, 0, sizeof (*new_al));
new_al->offset = offset;
return result;
}
+/* If there is a reason to penalize the function described by INFO in the
+ cloning goodness evaluation, do so. */
+
+static inline int64_t
+incorporate_penalties (ipa_node_params *info, int64_t evaluation)
+{
+ if (info->node_within_scc)
+ evaluation = (evaluation
+ * (100 - PARAM_VALUE (PARAM_IPA_CP_RECURSION_PENALTY))) / 100;
+
+ if (info->node_calling_single_call)
+ evaluation = (evaluation
+ * (100 - PARAM_VALUE (PARAM_IPA_CP_SINGLE_CALL_PENALTY)))
+ / 100;
+
+ return evaluation;
+}
+
/* Return true if cloning NODE is a good idea, given the estimated TIME_BENEFIT
and SIZE_COST and with the sum of frequencies of incoming edges to the
potential new clone in FREQUENCIES. */
gcc_assert (size_cost > 0);
+ struct ipa_node_params *info = IPA_NODE_REF (node);
if (max_count)
{
int factor = (count_sum * 1000) / max_count;
int64_t evaluation = (((int64_t) time_benefit * factor)
/ size_cost);
+ evaluation = incorporate_penalties (info, evaluation);
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, " good_cloning_opportunity_p (time: %i, "
"size: %i, count_sum: " HOST_WIDE_INT_PRINT_DEC
- ") -> evaluation: " "%"PRId64
+ "%s%s) -> evaluation: " "%" PRId64
", threshold: %i\n",
time_benefit, size_cost, (HOST_WIDE_INT) count_sum,
+ info->node_within_scc ? ", scc" : "",
+ info->node_calling_single_call ? ", single_call" : "",
evaluation, PARAM_VALUE (PARAM_IPA_CP_EVAL_THRESHOLD));
return evaluation >= PARAM_VALUE (PARAM_IPA_CP_EVAL_THRESHOLD);
{
int64_t evaluation = (((int64_t) time_benefit * freq_sum)
/ size_cost);
+ evaluation = incorporate_penalties (info, evaluation);
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, " good_cloning_opportunity_p (time: %i, "
- "size: %i, freq_sum: %i) -> evaluation: "
- "%"PRId64 ", threshold: %i\n",
- time_benefit, size_cost, freq_sum, evaluation,
- PARAM_VALUE (PARAM_IPA_CP_EVAL_THRESHOLD));
+ "size: %i, freq_sum: %i%s%s) -> evaluation: "
+ "%" PRId64 ", threshold: %i\n",
+ time_benefit, size_cost, freq_sum,
+ info->node_within_scc ? ", scc" : "",
+ info->node_calling_single_call ? ", single_call" : "",
+ evaluation, PARAM_VALUE (PARAM_IPA_CP_EVAL_THRESHOLD));
return evaluation >= PARAM_VALUE (PARAM_IPA_CP_EVAL_THRESHOLD);
}
struct cgraph_edge *cs;
for (cs = v->callees; cs; cs = cs->next_callee)
- if (ipa_edge_within_scc (cs)
- && propagate_constants_accross_call (cs))
- push_node_to_stack (topo, cs->callee);
+ if (ipa_edge_within_scc (cs))
+ {
+ IPA_NODE_REF (v)->node_within_scc = true;
+ if (propagate_constants_accross_call (cs))
+ push_node_to_stack (topo, cs->callee->function_symbol ());
+ }
v = pop_node_from_stack (topo);
}
bool dumped_sth = false;
bool found_useful_result = false;
+ if (!opt_for_fn (node->decl, flag_ipa_cp_alignment))
+ {
+ if (dump_file)
+ fprintf (dump_file, "Not considering %s for alignment discovery "
+ "and propagate; -fipa-cp-alignment: disabled.\n",
+ node->name ());
+ continue;
+ }
+
if (info->ipcp_orig_node)
info = IPA_NODE_REF (info->ipcp_orig_node);
edge_removal_hook_holder =
symtab->add_edge_removal_hook (&ipcp_edge_removal_hook, NULL);
- ipcp_cst_values_pool = create_alloc_pool ("IPA-CP constant values",
- sizeof (ipcp_value<tree>), 32);
- ipcp_poly_ctx_values_pool = create_alloc_pool
- ("IPA-CP polymorphic contexts",
- sizeof (ipcp_value<ipa_polymorphic_call_context>), 32);
- ipcp_sources_pool = create_alloc_pool ("IPA-CP value sources",
- sizeof (ipcp_value_source<tree>), 64);
- ipcp_agg_lattice_pool = create_alloc_pool ("IPA_CP aggregate lattices",
- sizeof (struct ipcp_agg_lattice),
- 32);
if (dump_file)
{
fprintf (dump_file, "\nIPA structures before propagation:\n");
/* Free all IPCP structures. */
free_toporder_info (&topo);
next_edge_clone.release ();
+ prev_edge_clone.release ();
symtab->remove_edge_removal_hook (edge_removal_hook_holder);
symtab->remove_edge_duplication_hook (edge_duplication_hook_holder);
ipa_free_all_structures_after_ipa_cp ();