===================================================================
@@ -258,6 +258,8 @@ class ipcp_param_lattices
public:
/* Lattice describing the value of the parameter itself. */
ipcp_lattice<tree> itself;
+ /* Lattice describing the the polymorphic contexts of a parameter. */
+ ipcp_lattice<ipa_polymorphic_call_context> ctxlat;
/* Lattices describing aggregate parts. */
ipcp_agg_lattice *aggs;
/* Number of aggregate lattices */
@@ -278,7 +280,8 @@ public:
/* Allocation pools for values and their sources in ipa-cp. */
-alloc_pool ipcp_values_pool;
+alloc_pool ipcp_cst_values_pool;
+alloc_pool ipcp_poly_ctx_values_pool;
alloc_pool ipcp_sources_pool;
alloc_pool ipcp_agg_lattice_pool;
@@ -310,6 +313,15 @@ ipa_get_scalar_lat (struct ipa_node_para
return &plats->itself;
}
+/* Return the lattice corresponding to the scalar value of the Ith formal
+ parameter of the function described by INFO. */
+static inline ipcp_lattice<ipa_polymorphic_call_context> *
+ipa_get_poly_ctx_lat (struct ipa_node_params *info, int i)
+{
+ struct ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
+ return &plats->ctxlat;
+}
+
/* Return whether LAT is a lattice with a single constant and without an
undefined value. */
@@ -343,6 +355,14 @@ print_ipcp_constant_value (FILE * f, tre
print_generic_expr (f, v, 0);
}
+/* Print V which is extracted from a value in a lattice to F. */
+
+static void
+print_ipcp_constant_value (FILE * f, ipa_polymorphic_call_context v)
+{
+ v.dump(f, false);
+}
+
/* Print a lattice LAT to F. */
template <typename valtype>
@@ -427,7 +447,8 @@ print_all_lattices (FILE * f, bool dump_
struct ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
fprintf (f, " param [%d]: ", i);
plats->itself.print (f, dump_sources, dump_benefits);
-
+ fprintf (f, " ctxs: ");
+ plats->ctxlat.print (f, dump_sources, dump_benefits);
if (plats->virt_call)
fprintf (f, " virt_call flag set\n");
@@ -639,6 +660,7 @@ public:
int nnodes, stack_top;
value_topo_info<tree> constants;
+ value_topo_info<ipa_polymorphic_call_context> contexts;
ipa_topo_info () : order(NULL), stack(NULL), nnodes(0), stack_top(0),
constants ()
@@ -750,9 +772,10 @@ set_agg_lats_contain_variable (struct ip
static inline bool
set_all_contains_variable (struct ipcp_param_lattices *plats)
{
- bool ret = !plats->itself.contains_variable || !plats->aggs_contain_variable;
- plats->itself.contains_variable = true;
- plats->aggs_contain_variable = true;
+ bool ret;
+ ret = plats->itself.set_contains_variable ();
+ ret |= plats->ctxlat.set_contains_variable ();
+ ret |= set_agg_lats_contain_variable (plats);
return ret;
}
@@ -787,6 +810,7 @@ initialize_node_lattices (struct cgraph_
if (disable)
{
plats->itself.set_to_bottom ();
+ plats->ctxlat.set_to_bottom ();
set_agg_lats_to_bottom (plats);
}
else
@@ -853,28 +877,8 @@ ipa_get_jf_pass_through_result (struct i
static tree
ipa_get_jf_ancestor_result (struct ipa_jump_func *jfunc, tree input)
{
- if (TREE_CODE (input) == TREE_BINFO)
- {
- if (!ipa_get_jf_ancestor_type_preserved (jfunc))
- return NULL;
- /* FIXME: At LTO we can't propagate to non-polymorphic type, because
- we have no ODR equivalency on those. This should be fixed by
- propagating on types rather than binfos that would make type
- matching here unnecesary. */
- if (in_lto_p
- && (TREE_CODE (ipa_get_jf_ancestor_type (jfunc)) != RECORD_TYPE
- || !TYPE_BINFO (ipa_get_jf_ancestor_type (jfunc))
- || !BINFO_VTABLE (TYPE_BINFO (ipa_get_jf_ancestor_type (jfunc)))))
- {
- if (!ipa_get_jf_ancestor_offset (jfunc))
- return input;
- return NULL;
- }
- return get_binfo_at_offset (input,
- ipa_get_jf_ancestor_offset (jfunc),
- ipa_get_jf_ancestor_type (jfunc));
- }
- else if (TREE_CODE (input) == ADDR_EXPR)
+ gcc_checking_assert (TREE_CODE (input) != TREE_BINFO);
+ if (TREE_CODE (input) == ADDR_EXPR)
{
tree t = TREE_OPERAND (input, 0);
t = build_ref_for_offset (EXPR_LOCATION (t), t,
@@ -888,9 +892,9 @@ ipa_get_jf_ancestor_result (struct ipa_j
return NULL_TREE;
}
-/* Determine whether JFUNC evaluates to a known value (that is either a
- constant or a binfo) and if so, return it. Otherwise return NULL. INFO
- describes the caller node so that pass-through jump functions can be
+/* Determine whether JFUNC evaluates to a single known constant value and if
+ so, return it. Otherwise return NULL. INFO describes the caller node or
+ the one it is inlined to, so that pass-through jump functions can be
evaluated. */
tree
@@ -898,8 +902,6 @@ ipa_value_from_jfunc (struct ipa_node_pa
{
if (jfunc->type == IPA_JF_CONST)
return ipa_get_jf_constant (jfunc);
- else if (jfunc->type == IPA_JF_KNOWN_TYPE)
- return ipa_binfo_from_known_type_jfunc (jfunc);
else if (jfunc->type == IPA_JF_PASS_THROUGH
|| jfunc->type == IPA_JF_ANCESTOR)
{
@@ -912,7 +914,7 @@ ipa_value_from_jfunc (struct ipa_node_pa
idx = ipa_get_jf_ancestor_formal_id (jfunc);
if (info->ipcp_orig_node)
- input = info->known_vals[idx];
+ input = info->known_csts[idx];
else
{
ipcp_lattice<tree> *lat;
@@ -940,6 +942,68 @@ ipa_value_from_jfunc (struct ipa_node_pa
return NULL_TREE;
}
+/* Determie whether JFUNC evaluates to single known polymorphic context, given
+ that INFO describes the caller node or the one it is inlined to, CS is the
+ call graph edge corresponding to JFUNC and CSIDX index of the described
+ parameter. */
+
+ipa_polymorphic_call_context
+ipa_context_from_jfunc (ipa_node_params *info, cgraph_edge *cs, int csidx,
+ ipa_jump_func *jfunc)
+{
+ ipa_edge_args *args = IPA_EDGE_REF (cs);
+ ipa_polymorphic_call_context ctx;
+ ipa_polymorphic_call_context *edge_ctx
+ = cs ? ipa_get_ith_polymorhic_call_context (args, csidx) : NULL;
+
+ if (edge_ctx && !edge_ctx->useless_p ())
+ ctx = *edge_ctx;
+
+ if (jfunc->type == IPA_JF_PASS_THROUGH
+ || jfunc->type == IPA_JF_ANCESTOR)
+ {
+ ipa_polymorphic_call_context srcctx;
+ int srcidx;
+ if (jfunc->type == IPA_JF_PASS_THROUGH)
+ {
+ if (ipa_get_jf_pass_through_operation (jfunc) != NOP_EXPR
+ || !ipa_get_jf_pass_through_type_preserved (jfunc))
+ return ctx;
+ srcidx = ipa_get_jf_pass_through_formal_id (jfunc);
+ }
+ else
+ {
+ if (!ipa_get_jf_ancestor_type_preserved (jfunc))
+ return ctx;
+ srcidx = ipa_get_jf_ancestor_formal_id (jfunc);
+ }
+ if (info->ipcp_orig_node)
+ {
+ if (info->known_contexts.exists ())
+ srcctx = info->known_contexts[srcidx];
+ }
+ else
+ {
+ if (!info->lattices)
+ {
+ gcc_checking_assert (!flag_ipa_cp);
+ return ctx;
+ }
+ ipcp_lattice<ipa_polymorphic_call_context> *lat;
+ lat = ipa_get_poly_ctx_lat (info, srcidx);
+ if (!lat->is_single_const ())
+ return ctx;
+ srcctx = lat->values->value;
+ }
+ if (srcctx.useless_p ())
+ return ctx;
+ if (jfunc->type == IPA_JF_ANCESTOR)
+ srcctx.offset_by (ipa_get_jf_ancestor_offset (jfunc));
+ ctx.combine_with (srcctx);
+ }
+
+ return ctx;
+}
/* If checking is enabled, verify that no lattice is in the TOP state, i.e. not
bottom, not containing a variable component and without any known value at
@@ -1000,6 +1064,16 @@ values_equal_for_ipcp_p (tree x, tree y)
return operand_equal_p (x, y, 0);
}
+/* Return true iff X and Y should be considered equal contexts by IPA-CP. */
+
+static bool
+values_equal_for_ipcp_p (ipa_polymorphic_call_context x,
+ ipa_polymorphic_call_context y)
+{
+ return x.equal_to (y);
+}
+
+
/* Add a new value source to the value represented by THIS, marking that a
value comes from edge CS and (if the underlying jump function is a
pass-through or an ancestor one) from a caller value SRC_VAL of a caller
@@ -1031,7 +1105,22 @@ allocate_and_init_ipcp_value (tree sourc
{
ipcp_value<tree> *val;
- val = new (pool_alloc (ipcp_values_pool)) ipcp_value<tree>;
+ val = new (pool_alloc (ipcp_cst_values_pool)) ipcp_value<tree>;
+ memset (val, 0, sizeof (*val));
+ val->value = source;
+ return val;
+}
+
+/* Allocate a new ipcp_value holding a polymorphic context, initialize its
+ value to SOURCE and clear all other fields. */
+
+static ipcp_value<ipa_polymorphic_call_context> *
+allocate_and_init_ipcp_value (ipa_polymorphic_call_context source)
+{
+ ipcp_value<ipa_polymorphic_call_context> *val;
+
+ val = new (pool_alloc (ipcp_poly_ctx_values_pool))
+ ipcp_value<ipa_polymorphic_call_context>;
memset (val, 0, sizeof (*val));
val->value = source;
return val;
@@ -1171,19 +1260,9 @@ propagate_scalar_accross_jump_function (
if (dest_lat->bottom)
return false;
- if (jfunc->type == IPA_JF_CONST
- || jfunc->type == IPA_JF_KNOWN_TYPE)
+ if (jfunc->type == IPA_JF_CONST)
{
- tree val;
-
- if (jfunc->type == IPA_JF_KNOWN_TYPE)
- {
- val = ipa_binfo_from_known_type_jfunc (jfunc);
- if (!val)
- return dest_lat->set_contains_variable ();
- }
- else
- val = ipa_get_jf_constant (jfunc);
+ tree val = ipa_get_jf_constant (jfunc);
return dest_lat->add_value (val, cs, NULL, 0);
}
else if (jfunc->type == IPA_JF_PASS_THROUGH
@@ -1227,6 +1306,93 @@ propagate_scalar_accross_jump_function (
return dest_lat->set_contains_variable ();
}
+/* Propagate scalar values across jump function JFUNC that is associated with
+ edge CS and describes argument IDX and put the values into DEST_LAT. */
+
+static bool
+propagate_context_accross_jump_function (cgraph_edge *cs,
+ ipa_jump_func *jfunc, int idx,
+ ipcp_lattice<ipa_polymorphic_call_context> *dest_lat)
+{
+ ipa_edge_args *args = IPA_EDGE_REF (cs);
+ if (dest_lat->bottom)
+ return false;
+ bool ret = false;
+ bool added_sth = false;
+
+ ipa_polymorphic_call_context edge_ctx, *edge_ctx_ptr
+ = ipa_get_ith_polymorhic_call_context (args, idx);
+
+ if (edge_ctx_ptr)
+ {
+ edge_ctx = *edge_ctx_ptr;
+ edge_ctx.clear_speculation ();
+ }
+
+ if (jfunc->type == IPA_JF_PASS_THROUGH
+ || jfunc->type == IPA_JF_ANCESTOR)
+ {
+ struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller);
+ int src_idx;
+ ipcp_lattice<ipa_polymorphic_call_context> *src_lat;
+
+ /* TODO: Once we figure out how to propagate speculations, it will
+ probably be a good idea to switch to speculation if type_preserved is
+ not set instead of punting. */
+ if (jfunc->type == IPA_JF_PASS_THROUGH)
+ {
+ if (ipa_get_jf_pass_through_operation (jfunc) != NOP_EXPR
+ || !ipa_get_jf_pass_through_type_preserved (jfunc))
+ goto prop_fail;
+ src_idx = ipa_get_jf_pass_through_formal_id (jfunc);
+ }
+ else
+ {
+ if (!ipa_get_jf_ancestor_type_preserved (jfunc))
+ goto prop_fail;
+ src_idx = ipa_get_jf_ancestor_formal_id (jfunc);
+ }
+
+ src_lat = ipa_get_poly_ctx_lat (caller_info, src_idx);
+ /* If we would need to clone the caller and cannot, do not propagate. */
+ if (!ipcp_versionable_function_p (cs->caller)
+ && (src_lat->contains_variable
+ || (src_lat->values_count > 1)))
+ goto prop_fail;
+ if (src_lat->contains_variable)
+ ret |= dest_lat->set_contains_variable ();
+
+ ipcp_value<ipa_polymorphic_call_context> *src_val;
+ for (src_val = src_lat->values; src_val; src_val = src_val->next)
+ {
+ ipa_polymorphic_call_context cur = src_val->value;
+ if (jfunc->type == IPA_JF_ANCESTOR)
+ cur.offset_by (ipa_get_jf_ancestor_offset (jfunc));
+ /* TODO: Perhaps attempt to look up some used OTR type? */
+ cur.clear_speculation ();
+ if (!edge_ctx.useless_p ())
+ cur.combine_with (edge_ctx);
+ if (!cur.useless_p ())
+ {
+ ret |= dest_lat->add_value (cur, cs, src_val, src_idx);
+ added_sth = true;
+ }
+ }
+
+ }
+
+ prop_fail:
+ if (!added_sth)
+ {
+ if (!edge_ctx.useless_p ())
+ ret |= dest_lat->add_value (edge_ctx, cs);
+ else
+ ret |= dest_lat->set_contains_variable ();
+ }
+
+ return ret;
+}
+
/* If DEST_PLATS already has aggregate items, check that aggs_by_ref matches
NEW_AGGS_BY_REF and if not, mark all aggs as bottoms and return true (in all
other cases, return false). If there are no aggregate items, set
@@ -1561,6 +1727,8 @@ propagate_constants_accross_call (struct
{
ret |= propagate_scalar_accross_jump_function (cs, jump_func,
&dest_plats->itself);
+ ret |= propagate_context_accross_jump_function (cs, jump_func, i,
+ &dest_plats->ctxlat);
ret |= propagate_aggs_accross_jump_function (cs, jump_func,
dest_plats);
}
@@ -1572,25 +1740,24 @@ propagate_constants_accross_call (struct
}
/* If an indirect edge IE can be turned into a direct one based on KNOWN_VALS
- (which can contain both constants and binfos), KNOWN_BINFOS, KNOWN_AGGS or
+ (which can contain both constants and binfos), KNOWN_CONTEXTS, KNOWN_AGGS or
AGG_REPS return the destination. The latter three can be NULL. If AGG_REPS
is not NULL, KNOWN_AGGS is ignored. */
static tree
ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
- vec<tree> known_vals,
- vec<tree> known_binfos,
+ vec<tree> known_csts,
+ vec<ipa_polymorphic_call_context> known_contexts,
vec<ipa_agg_jump_function_p> known_aggs,
struct ipa_agg_replacement_value *agg_reps)
{
int param_index = ie->indirect_info->param_index;
- HOST_WIDE_INT token, anc_offset;
- tree otr_type;
+ HOST_WIDE_INT anc_offset;
tree t;
tree target = NULL;
if (param_index == -1
- || known_vals.length () <= (unsigned int) param_index)
+ || known_csts.length () <= (unsigned int) param_index)
return NULL_TREE;
if (!ie->indirect_info->polymorphic)
@@ -1625,7 +1792,7 @@ ipa_get_indirect_edge_target_1 (struct c
t = NULL;
}
else
- t = known_vals[param_index];
+ t = known_csts[param_index];
if (t &&
TREE_CODE (t) == ADDR_EXPR
@@ -1639,9 +1806,7 @@ ipa_get_indirect_edge_target_1 (struct c
return NULL_TREE;
gcc_assert (!ie->indirect_info->agg_contents);
- token = ie->indirect_info->otr_token;
anc_offset = ie->indirect_info->offset;
- otr_type = ie->indirect_info->otr_type;
t = NULL;
@@ -1695,42 +1860,43 @@ ipa_get_indirect_edge_target_1 (struct c
}
}
- /* Did we work out BINFO via type propagation? */
- if (!t && known_binfos.length () > (unsigned int) param_index)
- t = known_binfos[param_index];
- /* Or do we know the constant value of pointer? */
+ /* Do we know the constant value of pointer? */
if (!t)
- t = known_vals[param_index];
- if (!t)
- return NULL_TREE;
+ t = known_csts[param_index];
- if (TREE_CODE (t) != TREE_BINFO)
- {
- ipa_polymorphic_call_context context (t, ie->indirect_info->otr_type,
- anc_offset);
- vec <cgraph_node *>targets;
- bool final;
+ gcc_checking_assert (!t || TREE_CODE (t) != TREE_BINFO);
- targets = possible_polymorphic_call_targets
- (ie->indirect_info->otr_type,
- ie->indirect_info->otr_token,
- context, &final);
- if (!final || targets.length () > 1)
- return NULL_TREE;
- if (targets.length () == 1)
- target = targets[0]->decl;
- else
- target = ipa_impossible_devirt_target (ie, NULL_TREE);
+ ipa_polymorphic_call_context context;
+ if (known_contexts.length () > (unsigned int) param_index)
+ {
+ context = known_contexts[param_index];
+ if (t)
+ {
+ ipa_polymorphic_call_context ctx2 = ipa_polymorphic_call_context
+ (t, ie->indirect_info->otr_type, anc_offset);
+ if (!ctx2.useless_p ())
+ context.combine_with (ctx2, ie->indirect_info->otr_type);
+ }
}
+ else if (t)
+ context = ipa_polymorphic_call_context (t, ie->indirect_info->otr_type,
+ anc_offset);
else
- {
- tree binfo;
+ return NULL_TREE;
- binfo = get_binfo_at_offset (t, anc_offset, otr_type);
- if (!binfo)
- return NULL_TREE;
- target = gimple_get_virt_method_for_binfo (token, binfo);
- }
+ vec <cgraph_node *>targets;
+ bool final;
+
+ targets = possible_polymorphic_call_targets
+ (ie->indirect_info->otr_type,
+ ie->indirect_info->otr_token,
+ context, &final);
+ if (!final || targets.length () > 1)
+ return NULL_TREE;
+ if (targets.length () == 1)
+ target = targets[0]->decl;
+ else
+ target = ipa_impossible_devirt_target (ie, NULL_TREE);
if (target && !possible_polymorphic_call_target_p (ie,
cgraph_node::get (target)))
@@ -1740,27 +1906,27 @@ ipa_get_indirect_edge_target_1 (struct c
}
-/* If an indirect edge IE can be turned into a direct one based on KNOWN_VALS
- (which can contain both constants and binfos), KNOWN_BINFOS (which can be
- NULL) or KNOWN_AGGS (which also can be NULL) return the destination. */
+/* If an indirect edge IE can be turned into a direct one based on KNOWN_CSTS,
+ KNOWN_CONTEXTS (which can be vNULL) or KNOWN_AGGS (which also can be vNULL)
+ return the destination. */
tree
ipa_get_indirect_edge_target (struct cgraph_edge *ie,
- vec<tree> known_vals,
- vec<tree> known_binfos,
+ vec<tree> known_csts,
+ vec<ipa_polymorphic_call_context> known_contexts,
vec<ipa_agg_jump_function_p> known_aggs)
{
- return ipa_get_indirect_edge_target_1 (ie, known_vals, known_binfos,
+ return ipa_get_indirect_edge_target_1 (ie, known_csts, known_contexts,
known_aggs, NULL);
}
/* Calculate devirtualization time bonus for NODE, assuming we know KNOWN_CSTS
- and KNOWN_BINFOS. */
+ and KNOWN_CONTEXTS. */
static int
devirtualization_time_bonus (struct cgraph_node *node,
vec<tree> known_csts,
- vec<tree> known_binfos,
+ vec<ipa_polymorphic_call_context> known_contexts,
vec<ipa_agg_jump_function_p> known_aggs)
{
struct cgraph_edge *ie;
@@ -1773,7 +1939,7 @@ devirtualization_time_bonus (struct cgra
enum availability avail;
tree target;
- target = ipa_get_indirect_edge_target (ie, known_csts, known_binfos,
+ target = ipa_get_indirect_edge_target (ie, known_csts, known_contexts,
known_aggs);
if (!target)
continue;
@@ -1890,25 +2056,27 @@ context_independent_aggregate_values (st
return res;
}
-/* Allocate KNOWN_CSTS, KNOWN_BINFOS and, if non-NULL, KNOWN_AGGS and populate
- them with values of parameters that are known independent of the context.
- INFO describes the function. If REMOVABLE_PARAMS_COST is non-NULL, the
- movement cost of all removable parameters will be stored in it. */
+/* Allocate KNOWN_CSTS, KNOWN_CONTEXTS and, if non-NULL, KNOWN_AGGS and
+ populate them with values of parameters that are known independent of the
+ context. INFO describes the function. If REMOVABLE_PARAMS_COST is
+ non-NULL, the movement cost of all removable parameters will be stored in
+ it. */
static bool
gather_context_independent_values (struct ipa_node_params *info,
- vec<tree> *known_csts,
- vec<tree> *known_binfos,
- vec<ipa_agg_jump_function> *known_aggs,
- int *removable_params_cost)
+ vec<tree> *known_csts,
+ vec<ipa_polymorphic_call_context>
+ *known_contexts,
+ vec<ipa_agg_jump_function> *known_aggs,
+ int *removable_params_cost)
{
int i, count = ipa_get_param_count (info);
bool ret = false;
known_csts->create (0);
- known_binfos->create (0);
+ known_contexts->create (0);
known_csts->safe_grow_cleared (count);
- known_binfos->safe_grow_cleared (count);
+ known_contexts->safe_grow_cleared (count);
if (known_aggs)
{
known_aggs->create (0);
@@ -1926,28 +2094,25 @@ gather_context_independent_values (struc
if (lat->is_single_const ())
{
ipcp_value<tree> *val = lat->values;
- if (TREE_CODE (val->value) != TREE_BINFO)
- {
- (*known_csts)[i] = val->value;
- if (removable_params_cost)
- *removable_params_cost
- += estimate_move_cost (TREE_TYPE (val->value), false);
- ret = true;
- }
- else if (plats->virt_call)
- {
- (*known_binfos)[i] = val->value;
- ret = true;
- }
- else if (removable_params_cost
- && !ipa_is_param_used (info, i))
- *removable_params_cost += ipa_get_param_move_cost (info, i);
+ gcc_checking_assert (TREE_CODE (val->value) != TREE_BINFO);
+ (*known_csts)[i] = val->value;
+ if (removable_params_cost)
+ *removable_params_cost
+ += estimate_move_cost (TREE_TYPE (val->value), false);
+ ret = true;
}
else if (removable_params_cost
&& !ipa_is_param_used (info, i))
*removable_params_cost
+= ipa_get_param_move_cost (info, i);
+ ipcp_lattice<ipa_polymorphic_call_context> *ctxlat = &plats->ctxlat;
+ if (ctxlat->is_single_const ())
+ {
+ (*known_contexts)[i] = ctxlat->values->value;
+ ret = true;
+ }
+
if (known_aggs)
{
vec<ipa_agg_jf_item, va_gc> *agg_items;
@@ -1985,14 +2150,14 @@ agg_jmp_p_vec_for_t_vec (vec<ipa_agg_jum
}
/* Perform time and size measurement of NODE with the context given in
- KNOWN_CSTS, KNOWN_BINFOS and KNOWN_AGGS, calculate the benefit and cost
+ KNOWN_CSTS, KNOWN_CONTEXTS and KNOWN_AGGS, calculate the benefit and cost
given BASE_TIME of the node without specialization, REMOVABLE_PARAMS_COST of
all context-independent removable parameters and EST_MOVE_COST of estimated
movement of the considered parameter and store it into VAL. */
static void
perform_estimation_of_a_value (cgraph_node *node, vec<tree> known_csts,
- vec<tree> known_binfos,
+ vec<ipa_polymorphic_call_context> known_contexts,
vec<ipa_agg_jump_function_p> known_aggs_ptrs,
int base_time, int removable_params_cost,
int est_move_cost, ipcp_value_base *val)
@@ -2000,11 +2165,11 @@ perform_estimation_of_a_value (cgraph_no
int time, size, time_benefit;
inline_hints hints;
- estimate_ipcp_clone_size_and_time (node, known_csts, known_binfos,
+ estimate_ipcp_clone_size_and_time (node, known_csts, known_contexts,
known_aggs_ptrs, &size, &time,
&hints);
time_benefit = base_time - time
- + devirtualization_time_bonus (node, known_csts, known_binfos,
+ + devirtualization_time_bonus (node, known_csts, known_contexts,
known_aggs_ptrs)
+ hint_time_bonus (hints)
+ removable_params_cost + est_move_cost;
@@ -2029,7 +2194,8 @@ estimate_local_effects (struct cgraph_no
{
struct ipa_node_params *info = IPA_NODE_REF (node);
int i, count = ipa_get_param_count (info);
- vec<tree> known_csts, known_binfos;
+ vec<tree> known_csts;
+ vec<ipa_polymorphic_call_context> known_contexts;
vec<ipa_agg_jump_function> known_aggs;
vec<ipa_agg_jump_function_p> known_aggs_ptrs;
bool always_const;
@@ -2044,7 +2210,7 @@ estimate_local_effects (struct cgraph_no
node->name (), node->order, base_time);
always_const = gather_context_independent_values (info, &known_csts,
- &known_binfos, &known_aggs,
+ &known_contexts, &known_aggs,
&removable_params_cost);
known_aggs_ptrs = agg_jmp_p_vec_for_t_vec (known_aggs);
if (always_const)
@@ -2056,9 +2222,9 @@ estimate_local_effects (struct cgraph_no
init_caller_stats (&stats);
node->call_for_symbol_thunks_and_aliases (gather_caller_stats, &stats,
false);
- estimate_ipcp_clone_size_and_time (node, known_csts, known_binfos,
+ estimate_ipcp_clone_size_and_time (node, known_csts, known_contexts,
known_aggs_ptrs, &size, &time, &hints);
- time -= devirtualization_time_bonus (node, known_csts, known_binfos,
+ time -= devirtualization_time_bonus (node, known_csts, known_contexts,
known_aggs_ptrs);
time -= hint_time_bonus (hints);
time -= removable_params_cost;
@@ -2104,32 +2270,19 @@ estimate_local_effects (struct cgraph_no
struct ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
ipcp_lattice<tree> *lat = &plats->itself;
ipcp_value<tree> *val;
- int emc;
if (lat->bottom
|| !lat->values
- || known_csts[i]
- || known_binfos[i])
+ || known_csts[i])
continue;
for (val = lat->values; val; val = val->next)
{
- if (TREE_CODE (val->value) != TREE_BINFO)
- {
- known_csts[i] = val->value;
- known_binfos[i] = NULL_TREE;
- emc = estimate_move_cost (TREE_TYPE (val->value), true);
- }
- else if (plats->virt_call)
- {
- known_csts[i] = NULL_TREE;
- known_binfos[i] = val->value;
- emc = 0;
- }
- else
- continue;
+ gcc_checking_assert (TREE_CODE (val->value) != TREE_BINFO);
+ known_csts[i] = val->value;
- perform_estimation_of_a_value (node, known_csts, known_binfos,
+ int emc = estimate_move_cost (TREE_TYPE (val->value), true);
+ perform_estimation_of_a_value (node, known_csts, known_contexts,
known_aggs_ptrs, base_time,
removable_params_cost, emc, val);
@@ -2143,10 +2296,44 @@ estimate_local_effects (struct cgraph_no
val->local_time_benefit, val->local_size_cost);
}
}
- known_binfos[i] = NULL_TREE;
known_csts[i] = NULL_TREE;
}
+ for (i = 0; i < count; i++)
+ {
+ struct ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
+
+ if (!plats->virt_call)
+ continue;
+
+ ipcp_lattice<ipa_polymorphic_call_context> *ctxlat = &plats->ctxlat;
+ ipcp_value<ipa_polymorphic_call_context> *val;
+
+ if (ctxlat->bottom
+ || !ctxlat->values
+ || !known_contexts[i].useless_p ())
+ continue;
+
+ for (val = ctxlat->values; val; val = val->next)
+ {
+ known_contexts[i] = val->value;
+ perform_estimation_of_a_value (node, known_csts, known_contexts,
+ known_aggs_ptrs, base_time,
+ removable_params_cost, 0, val);
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, " - estimates for polymorphic context ");
+ print_ipcp_constant_value (dump_file, val->value);
+ fprintf (dump_file, " for ");
+ ipa_dump_param (dump_file, info, i);
+ fprintf (dump_file, ": time_benefit: %i, size: %i\n",
+ val->local_time_benefit, val->local_size_cost);
+ }
+ }
+ known_contexts[i] = ipa_polymorphic_call_context ();
+ }
+
for (i = 0; i < count ; i++)
{
struct ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
@@ -2174,7 +2361,7 @@ estimate_local_effects (struct cgraph_no
item.value = val->value;
vec_safe_push (ajf->items, item);
- perform_estimation_of_a_value (node, known_csts, known_binfos,
+ perform_estimation_of_a_value (node, known_csts, known_contexts,
known_aggs_ptrs, base_time,
removable_params_cost, 0, val);
@@ -2200,7 +2387,7 @@ estimate_local_effects (struct cgraph_no
vec_free (known_aggs[i].items);
known_csts.release ();
- known_binfos.release ();
+ known_contexts.release ();
known_aggs.release ();
known_aggs_ptrs.release ();
}
@@ -2274,17 +2461,30 @@ add_all_node_vals_to_toposort (cgraph_no
struct ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
ipcp_lattice<tree> *lat = &plats->itself;
struct ipcp_agg_lattice *aglat;
- ipcp_value<tree> *val;
if (!lat->bottom)
- for (val = lat->values; val; val = val->next)
- topo->constants.add_val (val);
+ {
+ ipcp_value<tree> *val;
+ for (val = lat->values; val; val = val->next)
+ topo->constants.add_val (val);
+ }
if (!plats->aggs_bottom)
for (aglat = plats->aggs; aglat; aglat = aglat->next)
if (!aglat->bottom)
- for (val = aglat->values; val; val = val->next)
- topo->constants.add_val (val);
+ {
+ ipcp_value<tree> *val;
+ for (val = aglat->values; val; val = val->next)
+ topo->constants.add_val (val);
+ }
+
+ ipcp_lattice<ipa_polymorphic_call_context> *ctxlat = &plats->ctxlat;
+ if (!ctxlat->bottom)
+ {
+ ipcp_value<ipa_polymorphic_call_context> *ctxval;
+ for (ctxval = ctxlat->values; ctxval; ctxval = ctxval->next)
+ topo->contexts.add_val (ctxval);
+ }
}
}
@@ -2389,8 +2589,8 @@ value_topo_info<valtype>::propagate_effe
}
-/* Propagate constants, binfos and their effects from the summaries
- interprocedurally. */
+/* Propagate constants, polymorphic contexts and their effects from the
+ summaries interprocedurally. */
static void
ipcp_propagate_stage (struct ipa_topo_info *topo)
@@ -2435,6 +2635,7 @@ ipcp_propagate_stage (struct ipa_topo_in
ipcp_verify_propagated_values ();
#endif
topo->constants.propagate_effects ();
+ topo->contexts.propagate_effects ();
if (dump_file)
{
@@ -2444,11 +2645,13 @@ ipcp_propagate_stage (struct ipa_topo_in
}
/* Discover newly direct outgoing edges from NODE which is a new clone with
- known KNOWN_VALS and make them direct. */
+ known KNOWN_CSTS and make them direct. */
static void
ipcp_discover_new_direct_edges (struct cgraph_node *node,
- vec<tree> known_vals,
+ vec<tree> known_csts,
+ vec<ipa_polymorphic_call_context>
+ known_contexts,
struct ipa_agg_replacement_value *aggvals)
{
struct cgraph_edge *ie, *next_ie;
@@ -2459,8 +2662,8 @@ ipcp_discover_new_direct_edges (struct c
tree target;
next_ie = ie->next_callee;
- target = ipa_get_indirect_edge_target_1 (ie, known_vals, vNULL, vNULL,
- aggvals);
+ target = ipa_get_indirect_edge_target_1 (ie, known_csts, known_contexts,
+ vNULL, aggvals);
if (target)
{
bool agg_contents = ie->indirect_info->agg_contents;
@@ -2589,7 +2792,7 @@ cgraph_edge_brings_value_p (struct cgrap
{
tree t;
if (src->offset == -1)
- t = caller_info->known_vals[src->index];
+ t = caller_info->known_csts[src->index];
else
t = get_clone_agg_value (cs->caller, src->offset, src->index);
return (t != NULL_TREE
@@ -2618,6 +2821,35 @@ cgraph_edge_brings_value_p (struct cgrap
}
}
+/* Return true if edge CS does bring about the value described by SRC. */
+
+static bool
+cgraph_edge_brings_value_p (struct cgraph_edge *cs,
+ ipcp_value_source<ipa_polymorphic_call_context>
+ *src)
+{
+ struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller);
+ cgraph_node *real_dest = cs->callee->function_symbol ();
+ struct ipa_node_params *dst_info = IPA_NODE_REF (real_dest);
+
+ if ((dst_info->ipcp_orig_node && !dst_info->is_all_contexts_clone)
+ || caller_info->node_dead)
+ return false;
+ if (!src->val)
+ return true;
+
+ if (caller_info->ipcp_orig_node)
+ return (caller_info->known_contexts.length () > (unsigned) src->index)
+ && values_equal_for_ipcp_p (src->val->value,
+ caller_info->known_contexts[src->index]);
+
+ struct ipcp_param_lattices *plats = ipa_get_parm_lattices (caller_info,
+ src->index);
+ return plats->ctxlat.is_single_const ()
+ && values_equal_for_ipcp_p (src->val->value,
+ plats->ctxlat.values->value);
+}
+
/* Get the next clone in the linked list of clones of an edge. */
static inline struct cgraph_edge *
@@ -2847,12 +3079,14 @@ update_specialized_profile (struct cgrap
dump_profile_updates (orig_node, new_node);
}
-/* Create a specialized version of NODE with known constants and types of
- parameters in KNOWN_VALS and redirect all edges in CALLERS to it. */
+/* Create a specialized version of NODE with known constants in KNOWN_CSTS,
+ known contexts in KNOWN_CONTEXTS and known aggregate values in AGGVALS and
+ redirect all edges in CALLERS to it. */
static struct cgraph_node *
create_specialized_node (struct cgraph_node *node,
- vec<tree> known_vals,
+ vec<tree> known_csts,
+ vec<ipa_polymorphic_call_context> known_contexts,
struct ipa_agg_replacement_value *aggvals,
vec<cgraph_edge *> callers)
{
@@ -2870,10 +3104,9 @@ create_specialized_node (struct cgraph_n
args_to_skip = BITMAP_GGC_ALLOC ();
for (i = 0; i < count; i++)
{
- tree t = known_vals[i];
+ tree t = known_csts[i];
- if ((t && TREE_CODE (t) != TREE_BINFO)
- || !ipa_is_param_used (info, i))
+ if (t || !ipa_is_param_used (info, i))
bitmap_set_bit (args_to_skip, i);
}
}
@@ -2886,11 +3119,12 @@ create_specialized_node (struct cgraph_n
for (i = 0; i < count ; i++)
{
- tree t = known_vals[i];
- if (t && TREE_CODE (t) != TREE_BINFO)
+ tree t = known_csts[i];
+ if (t)
{
struct ipa_replace_map *replace_map;
+ gcc_checking_assert (TREE_CODE (t) != TREE_BINFO);
replace_map = get_replacement_map (info, t, i);
if (replace_map)
vec_safe_push (replace_trees, replace_map);
@@ -2907,6 +3141,15 @@ create_specialized_node (struct cgraph_n
{
fprintf (dump_file, " the new node is %s/%i.\n",
new_node->name (), new_node->order);
+ if (known_contexts.exists ())
+ {
+ for (i = 0; i < count ; i++)
+ if (!known_contexts[i].useless_p ())
+ {
+ fprintf (dump_file, " known ctx %i is ", i);
+ known_contexts[i].dump (dump_file);
+ }
+ }
if (aggvals)
ipa_dump_agg_replacement_values (dump_file, aggvals);
}
@@ -2914,21 +3157,21 @@ create_specialized_node (struct cgraph_n
update_profiling_info (node, new_node);
new_info = IPA_NODE_REF (new_node);
new_info->ipcp_orig_node = node;
- new_info->known_vals = known_vals;
+ new_info->known_csts = known_csts;
+ new_info->known_contexts = known_contexts;
- ipcp_discover_new_direct_edges (new_node, known_vals, aggvals);
+ ipcp_discover_new_direct_edges (new_node, known_csts, known_contexts, aggvals);
callers.release ();
return new_node;
}
/* Given a NODE, and a subset of its CALLERS, try to populate blanks slots in
- KNOWN_VALS with constants and types that are also known for all of the
- CALLERS. */
+ KNOWN_CSTS with constants that are also known for all of the CALLERS. */
static void
find_more_scalar_values_for_callers_subset (struct cgraph_node *node,
- vec<tree> known_vals,
+ vec<tree> known_csts,
vec<cgraph_edge *> callers)
{
struct ipa_node_params *info = IPA_NODE_REF (node);
@@ -2940,7 +3183,7 @@ find_more_scalar_values_for_callers_subs
tree newval = NULL_TREE;
int j;
- if (ipa_get_scalar_lat (info, i)->bottom || known_vals[i])
+ if (ipa_get_scalar_lat (info, i)->bottom || known_csts[i])
continue;
FOR_EACH_VEC_ELT (callers, j, cs)
@@ -2977,8 +3220,77 @@ find_more_scalar_values_for_callers_subs
fprintf (dump_file, "\n");
}
- known_vals[i] = newval;
+ known_csts[i] = newval;
+ }
+ }
+}
+
+/* Given a NODE and a subset of its CALLERS, try to populate plank slots in
+ KNOWN_CONTEXTS with polymorphic contexts that are also known for all of the
+ CALLERS. */
+
+static void
+find_more_contexts_for_caller_subset (cgraph_node *node,
+ vec<ipa_polymorphic_call_context>
+ *known_contexts,
+ vec<cgraph_edge *> callers)
+{
+ ipa_node_params *info = IPA_NODE_REF (node);
+ int i, count = ipa_get_param_count (info);
+
+ for (i = 0; i < count ; i++)
+ {
+ cgraph_edge *cs;
+
+ if (ipa_get_poly_ctx_lat (info, i)->bottom
+ || (known_contexts->exists ()
+ && !(*known_contexts)[i].useless_p ()))
+ continue;
+
+ ipa_polymorphic_call_context newval;
+ bool found = false;
+ int j;
+
+ FOR_EACH_VEC_ELT (callers, j, cs)
+ {
+ if (i >= ipa_get_cs_argument_count (IPA_EDGE_REF (cs)))
+ return;
+ ipa_jump_func *jfunc = ipa_get_ith_jump_func (IPA_EDGE_REF (cs),
+ i);
+ ipa_polymorphic_call_context ctx;
+ ctx = ipa_context_from_jfunc (IPA_NODE_REF (cs->caller), cs, i,
+ jfunc);
+ ctx.clear_speculation ();
+ if (ctx.useless_p ()
+ || (found && !values_equal_for_ipcp_p (newval, ctx)))
+ {
+ found = false;
+ break;
+ }
+ else if (!found)
+ {
+ found = true;
+ newval = ctx;
+ }
+ }
+
+ if (found)
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, " adding an extra known polymorphic "
+ "context ");
+ print_ipcp_constant_value (dump_file, newval);
+ fprintf (dump_file, " for ");
+ ipa_dump_param (dump_file, info, i);
+ fprintf (dump_file, "\n");
+ }
+
+ if (!known_contexts->exists ())
+ known_contexts->safe_grow_cleared (ipa_get_param_count (info));
+ (*known_contexts)[i] = newval;
}
+
}
}
@@ -3355,7 +3667,7 @@ cgraph_edge_brings_all_scalars_for_node
struct ipa_jump_func *jump_func;
tree val, t;
- val = dest_info->known_vals[i];
+ val = dest_info->known_csts[i];
if (!val)
continue;
@@ -3489,28 +3801,70 @@ perhaps_add_new_callers (cgraph_node *no
update_specialized_profile (val->spec_node, node, redirected_sum);
}
+/* Return true if KNOWN_CONTEXTS contain at least one useful context. */
+
+static bool
+known_contexts_useful_p (vec<ipa_polymorphic_call_context> known_contexts)
+{
+ ipa_polymorphic_call_context *ctx;
+ int i;
+
+ FOR_EACH_VEC_ELT (known_contexts, i, ctx)
+ if (!ctx->useless_p ())
+ return true;
+ return false;
+}
+
+/* Return a copy of KNOWN_CSTS if it is not empty, otherwise return vNULL. */
+
+static vec<ipa_polymorphic_call_context>
+copy_useful_known_contexts (vec<ipa_polymorphic_call_context> known_contexts)
+{
+ if (known_contexts_useful_p (known_contexts))
+ return known_contexts.copy ();
+ else
+ return vNULL;
+}
-/* Copy KNOWN_BINFOS to KNOWN_VALS. */
+/* Copy KNOWN_CSTS and modify the copy according to VAL and INDEX. If
+ non-empty, replace KNOWN_CONTEXTS with its copy too. */
static void
-move_binfos_to_values (vec<tree> known_vals,
- vec<tree> known_binfos)
+modify_known_vectors_with_val (vec<tree> *known_csts,
+ vec<ipa_polymorphic_call_context> *known_contexts,
+ ipcp_value<tree> *val,
+ int index)
{
- tree t;
- int i;
+ *known_csts = known_csts->copy ();
+ *known_contexts = copy_useful_known_contexts (*known_contexts);
+ (*known_csts)[index] = val->value;
+}
- for (i = 0; known_binfos.iterate (i, &t); i++)
- if (t)
- known_vals[i] = t;
+/* Replace KNOWN_CSTS with its copy. Also copy KNOWN_CONTEXTS and modify the
+ copy according to VAL and INDEX. */
+
+static void
+modify_known_vectors_with_val (vec<tree> *known_csts,
+ vec<ipa_polymorphic_call_context> *known_contexts,
+ ipcp_value<ipa_polymorphic_call_context> *val,
+ int index)
+{
+ *known_csts = known_csts->copy ();
+ *known_contexts = known_contexts->copy ();
+ (*known_contexts)[index] = val->value;
}
-/* Return true if there is a replacement equivalent to VALUE, INDEX and OFFSET
- among those in the AGGVALS list. */
+/* Return true if OFFSET indicates this was not an aggregate value or there is
+ a replacement equivalent to VALUE, INDEX and OFFSET among those in the
+ AGGVALS list. */
DEBUG_FUNCTION bool
-ipcp_val_in_agg_replacements_p (struct ipa_agg_replacement_value *aggvals,
- int index, HOST_WIDE_INT offset, tree value)
+ipcp_val_agg_replacement_ok_p (ipa_agg_replacement_value *aggvals,
+ int index, HOST_WIDE_INT offset, tree value)
{
+ if (offset == -1)
+ return true;
+
while (aggvals)
{
if (aggvals->index == index
@@ -3522,22 +3876,32 @@ ipcp_val_in_agg_replacements_p (struct i
return false;
}
+/* Return true if offset is minus one because source of a polymorphic contect
+ cannot be an aggregate value. */
+
+DEBUG_FUNCTION bool
+ipcp_val_agg_replacement_ok_p (ipa_agg_replacement_value *,
+ int , HOST_WIDE_INT offset,
+ ipa_polymorphic_call_context)
+{
+ return offset == -1;
+}
+
/* Decide wheter to create a special version of NODE for value VAL of parameter
at the given INDEX. If OFFSET is -1, the value is for the parameter itself,
otherwise it is stored at the given OFFSET of the parameter. KNOWN_CSTS,
- KNOWN_BINFOS and KNOWN_AGGS describe the other already known values. */
+ KNOWN_CONTEXTS and KNOWN_AGGS describe the other already known values. */
template <typename valtype>
static bool
decide_about_value (struct cgraph_node *node, int index, HOST_WIDE_INT offset,
ipcp_value<valtype> *val, vec<tree> known_csts,
- vec<tree> known_binfos)
+ vec<ipa_polymorphic_call_context> known_contexts)
{
struct ipa_agg_replacement_value *aggvals;
int freq_sum, caller_count;
gcov_type count_sum;
vec<cgraph_edge *> callers;
- vec<tree> kv;
if (val->spec_node)
{
@@ -3583,16 +3947,20 @@ decide_about_value (struct cgraph_node *
node->name (), node->order);
callers = gather_edges_for_value (val, caller_count);
- kv = known_csts.copy ();
- move_binfos_to_values (kv, known_binfos);
if (offset == -1)
- kv[index] = val->value;
- find_more_scalar_values_for_callers_subset (node, kv, callers);
+ modify_known_vectors_with_val (&known_csts, &known_contexts, val, index);
+ else
+ {
+ known_csts = known_csts.copy ();
+ known_contexts = copy_useful_known_contexts (known_contexts);
+ }
+ find_more_scalar_values_for_callers_subset (node, known_csts, callers);
+ find_more_contexts_for_caller_subset (node, &known_contexts, callers);
aggvals = find_aggregate_values_for_callers_subset (node, callers);
- gcc_checking_assert (offset == -1
- || ipcp_val_in_agg_replacements_p (aggvals, index,
- offset, val->value));
- val->spec_node = create_specialized_node (node, kv, aggvals, callers);
+ gcc_checking_assert (ipcp_val_agg_replacement_ok_p (aggvals, index,
+ offset, val->value));
+ val->spec_node = create_specialized_node (node, known_csts, known_contexts,
+ aggvals, callers);
overall_size += val->local_size_cost;
/* TODO: If for some lattice there is only one other known value
@@ -3608,7 +3976,8 @@ decide_whether_version_node (struct cgra
{
struct ipa_node_params *info = IPA_NODE_REF (node);
int i, count = ipa_get_param_count (info);
- vec<tree> known_csts, known_binfos;
+ vec<tree> known_csts;
+ vec<ipa_polymorphic_call_context> known_contexts;
vec<ipa_agg_jump_function> known_aggs = vNULL;
bool ret = false;
@@ -3619,7 +3988,7 @@ decide_whether_version_node (struct cgra
fprintf (dump_file, "\nEvaluating opportunities for %s/%i.\n",
node->name (), node->order);
- gather_context_independent_values (info, &known_csts, &known_binfos,
+ gather_context_independent_values (info, &known_csts, &known_contexts,
info->do_clone_for_all_contexts ? &known_aggs
: NULL, NULL);
@@ -3627,14 +3996,16 @@ decide_whether_version_node (struct cgra
{
struct ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
ipcp_lattice<tree> *lat = &plats->itself;
- ipcp_value<tree> *val;
+ ipcp_lattice<ipa_polymorphic_call_context> *ctxlat = &plats->ctxlat;
if (!lat->bottom
- && !known_csts[i]
- && !known_binfos[i])
- for (val = lat->values; val; val = val->next)
- ret |= decide_about_value (node, i, -1, val, known_csts,
- known_binfos);
+ && !known_csts[i])
+ {
+ ipcp_value<tree> *val;
+ for (val = lat->values; val; val = val->next)
+ ret |= decide_about_value (node, i, -1, val, known_csts,
+ known_contexts);
+ }
if (!plats->aggs_bottom)
{
@@ -3648,8 +4019,18 @@ decide_whether_version_node (struct cgra
|| !aglat->is_single_const ()))
for (val = aglat->values; val; val = val->next)
ret |= decide_about_value (node, i, aglat->offset, val,
- known_csts, known_binfos);
+ known_csts, known_contexts);
}
+
+ if (!ctxlat->bottom
+ && known_contexts[i].useless_p ())
+ {
+ ipcp_value<ipa_polymorphic_call_context> *val;
+ for (val = ctxlat->values; val; val = val->next)
+ ret |= decide_about_value (node, i, -1, val, known_csts,
+ known_contexts);
+ }
+
info = IPA_NODE_REF (node);
}
@@ -3664,8 +4045,13 @@ decide_whether_version_node (struct cgra
node->order);
callers = node->collect_callers ();
- move_binfos_to_values (known_csts, known_binfos);
- clone = create_specialized_node (node, known_csts,
+
+ if (!known_contexts_useful_p (known_contexts))
+ {
+ known_contexts.release ();
+ known_contexts = vNULL;
+ }
+ clone = create_specialized_node (node, known_csts, known_contexts,
known_aggs_to_agg_replacement_list (known_aggs),
callers);
info = IPA_NODE_REF (node);
@@ -3677,9 +4063,11 @@ decide_whether_version_node (struct cgra
ret = true;
}
else
- known_csts.release ();
+ {
+ known_csts.release ();
+ known_contexts.release ();
+ }
- known_binfos.release ();
return ret;
}
@@ -3803,8 +4191,11 @@ ipcp_driver (void)
edge_removal_hook_holder =
symtab->add_edge_removal_hook (&ipcp_edge_removal_hook, NULL);
- ipcp_values_pool = create_alloc_pool ("IPA-CP values",
- sizeof (ipcp_value<tree>), 32);
+ 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",
===================================================================
@@ -380,8 +380,14 @@ ipa_print_node_jump_functions_for_edge (
fprintf (f, "\n");
}
}
- if (IPA_EDGE_REF (cs)->polymorphic_call_contexts)
- ipa_get_ith_polymorhic_call_context (IPA_EDGE_REF (cs), i)->dump (f);
+
+ struct ipa_polymorphic_call_context *ctx
+ = ipa_get_ith_polymorhic_call_context (IPA_EDGE_REF (cs), i);
+ if (ctx && !ctx->useless_p ())
+ {
+ fprintf (f, " Context: ");
+ ctx->dump (dump_file);
+ }
}
}
@@ -559,7 +565,8 @@ ipa_set_ancestor_jf (struct ipa_jump_fun
type = NULL_TREE;
if (type)
type = TYPE_MAIN_VARIANT (type);
- gcc_assert (!type_preserved || contains_polymorphic_type_p (type));
+ if (!type || !contains_polymorphic_type_p (type))
+ type_preserved = false;
jfunc->type = IPA_JF_ANCESTOR;
jfunc->value.ancestor.formal_id = formal_id;
jfunc->value.ancestor.offset = offset;
@@ -2622,9 +2629,12 @@ combine_known_type_and_ancestor_jfs (str
+ ipa_get_jf_ancestor_offset (dst);
combined_type = ipa_get_jf_ancestor_type (dst);
- ipa_set_jf_known_type (dst, combined_offset,
- ipa_get_jf_known_type_base_type (src),
- combined_type);
+ if (combined_type)
+ ipa_set_jf_known_type (dst, combined_offset,
+ ipa_get_jf_known_type_base_type (src),
+ combined_type);
+ else
+ dst->type = IPA_JF_UNKNOWN;
}
/* Update the jump functions associated with call graph edge E when the call
@@ -2669,7 +2679,7 @@ update_jump_functions_after_inlining (st
struct ipa_polymorphic_call_context ctx = *src_ctx;
/* TODO: Make type preserved safe WRT contexts. */
- if (!dst->value.ancestor.agg_preserved)
+ if (!ipa_get_jf_ancestor_type_preserved (dst))
ctx.possible_dynamic_type_change (e->in_polymorphic_cdtor);
ctx.offset_by (dst->value.ancestor.offset);
if (!ctx.useless_p ())
@@ -2678,6 +2688,7 @@ update_jump_functions_after_inlining (st
count);
dst_ctx = ipa_get_ith_polymorhic_call_context (args, i);
}
+ dst_ctx->combine_with (ctx);
}
if (src->agg.items
@@ -2739,7 +2750,7 @@ update_jump_functions_after_inlining (st
struct ipa_polymorphic_call_context ctx = *src_ctx;
/* TODO: Make type preserved safe WRT contexts. */
- if (!dst->value.ancestor.agg_preserved)
+ if (!ipa_get_jf_pass_through_type_preserved (dst))
ctx.possible_dynamic_type_change (e->in_polymorphic_cdtor);
if (!ctx.useless_p ())
{
@@ -3152,41 +3163,24 @@ ipa_impossible_devirt_target (struct cgr
/* Try to find a destination for indirect edge IE that corresponds to a virtual
call based on a formal parameter which is described by jump function JFUNC
and if it can be determined, make it direct and return the direct edge.
- Otherwise, return NULL. NEW_ROOT_INFO is the node info that JFUNC lattices
- are relative to. */
+ Otherwise, return NULL. CTX describes the polymorphic context that the
+ parameter the call is based on brings along with it. */
static struct cgraph_edge *
try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
struct ipa_jump_func *jfunc,
- struct ipa_node_params *new_root_info,
- struct ipa_polymorphic_call_context *ctx_ptr)
+ struct ipa_polymorphic_call_context ctx)
{
- tree binfo, target = NULL;
+ tree target = NULL;
bool speculative = false;
- bool updated = false;
if (!flag_devirtualize)
return NULL;
- /* If this is call of a function parameter, restrict its type
- based on knowlede of the context. */
- if (ctx_ptr && !ie->indirect_info->by_ref)
- {
- struct ipa_polymorphic_call_context ctx = *ctx_ptr;
-
- ctx.offset_by (ie->indirect_info->offset);
-
- if (ie->indirect_info->vptr_changed)
- ctx.possible_dynamic_type_change (ie->in_polymorphic_cdtor,
- ie->indirect_info->otr_type);
-
- updated = ie->indirect_info->context.combine_with
- (ctx, ie->indirect_info->otr_type);
- }
+ gcc_assert (!ie->indirect_info->by_ref);
/* Try to do lookup via known virtual table pointer value. */
- if (!ie->indirect_info->by_ref
- && (!ie->indirect_info->vptr_changed || flag_devirtualize_speculatively))
+ if (!ie->indirect_info->vptr_changed || flag_devirtualize_speculatively)
{
tree vtable;
unsigned HOST_WIDE_INT offset;
@@ -3217,67 +3211,44 @@ try_make_edge_direct_virtual_call (struc
}
}
- binfo = ipa_value_from_jfunc (new_root_info, jfunc);
-
- if (binfo && TREE_CODE (binfo) != TREE_BINFO)
+ ipa_polymorphic_call_context ie_context (ie);
+ vec <cgraph_node *>targets;
+ bool final;
+
+ ctx.offset_by (ie->indirect_info->offset);
+ if (ie->indirect_info->vptr_changed)
+ ctx.possible_dynamic_type_change (ie->in_polymorphic_cdtor,
+ ie->indirect_info->otr_type);
+ ctx.combine_with (ie_context, ie->indirect_info->otr_type);
+ targets = possible_polymorphic_call_targets
+ (ie->indirect_info->otr_type,
+ ie->indirect_info->otr_token,
+ ctx, &final);
+ if (final && targets.length () <= 1)
{
- struct ipa_polymorphic_call_context ctx (binfo,
- ie->indirect_info->otr_type,
- ie->indirect_info->offset);
- updated |= ie->indirect_info->context.combine_with
- (ctx, ie->indirect_info->otr_type);
+ if (targets.length () == 1)
+ target = targets[0]->decl;
+ else
+ target = ipa_impossible_devirt_target (ie, NULL_TREE);
}
-
- if (updated)
+ else if (!target && flag_devirtualize_speculatively
+ && !ie->speculative && ie->maybe_hot_p ())
{
- ipa_polymorphic_call_context context (ie);
- vec <cgraph_node *>targets;
- bool final;
-
- targets = possible_polymorphic_call_targets
- (ie->indirect_info->otr_type,
- ie->indirect_info->otr_token,
- context, &final);
- if (final && targets.length () <= 1)
+ cgraph_node *n;
+ n = try_speculative_devirtualization (ie->indirect_info->otr_type,
+ ie->indirect_info->otr_token,
+ ie->indirect_info->context);
+ if (n)
{
- if (targets.length () == 1)
- target = targets[0]->decl;
- else
- target = ipa_impossible_devirt_target (ie, NULL_TREE);
- }
- else if (!target && flag_devirtualize_speculatively
- && !ie->speculative && ie->maybe_hot_p ())
- {
- cgraph_node *n = try_speculative_devirtualization (ie->indirect_info->otr_type,
- ie->indirect_info->otr_token,
- ie->indirect_info->context);
- if (n)
- {
- target = n->decl;
- speculative = true;
- }
- }
- }
-
- if (binfo && TREE_CODE (binfo) == TREE_BINFO)
- {
- binfo = get_binfo_at_offset (binfo, ie->indirect_info->offset,
- ie->indirect_info->otr_type);
- if (binfo)
- {
- tree t = gimple_get_virt_method_for_binfo (ie->indirect_info->otr_token,
- binfo);
- if (t)
- {
- target = t;
- speculative = false;
- }
+ target = n->decl;
+ speculative = true;
}
}
if (target)
{
- if (!possible_polymorphic_call_target_p (ie, cgraph_node::get_create (target)))
+ if (!possible_polymorphic_call_target_p
+ (ie, cgraph_node::get_create (target)))
{
if (speculative)
return NULL;
@@ -3336,11 +3307,9 @@ update_indirect_edges_after_inlining (st
new_direct_edge = NULL;
else if (ici->polymorphic)
{
- ipa_polymorphic_call_context *ctx;
- ctx = ipa_get_ith_polymorhic_call_context (top, param_index);
- new_direct_edge = try_make_edge_direct_virtual_call (ie, jfunc,
- new_root_info,
- ctx);
+ ipa_polymorphic_call_context ctx;
+ ctx = ipa_context_from_jfunc (new_root_info, cs, param_index, jfunc);
+ new_direct_edge = try_make_edge_direct_virtual_call (ie, jfunc, ctx);
}
else
new_direct_edge = try_make_edge_direct_simple_call (ie, jfunc,
@@ -3474,7 +3443,7 @@ propagate_controlled_uses (struct cgraph
{
struct cgraph_node *n;
struct ipa_ref *ref;
- tree t = new_root_info->known_vals[src_idx];
+ tree t = new_root_info->known_csts[src_idx];
if (t && TREE_CODE (t) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (t, 0)) == FUNCTION_DECL
@@ -3617,7 +3586,8 @@ ipa_free_node_params_substructures (stru
free (info->lattices);
/* Lattice values and their sources are deallocated with their alocation
pool. */
- info->known_vals.release ();
+ info->known_csts.release ();
+ info->known_contexts.release ();
memset (info, 0, sizeof (*info));
}
@@ -3892,7 +3862,8 @@ ipa_free_all_structures_after_ipa_cp (vo
ipa_free_all_edge_args ();
ipa_free_all_node_params ();
free_alloc_pool (ipcp_sources_pool);
- free_alloc_pool (ipcp_values_pool);
+ free_alloc_pool (ipcp_cst_values_pool);
+ free_alloc_pool (ipcp_poly_ctx_values_pool);
free_alloc_pool (ipcp_agg_lattice_pool);
ipa_unregister_cgraph_hooks ();
if (ipa_refdesc_pool)
@@ -3911,8 +3882,10 @@ ipa_free_all_structures_after_iinln (voi
ipa_unregister_cgraph_hooks ();
if (ipcp_sources_pool)
free_alloc_pool (ipcp_sources_pool);
- if (ipcp_values_pool)
- free_alloc_pool (ipcp_values_pool);
+ if (ipcp_cst_values_pool)
+ free_alloc_pool (ipcp_cst_values_pool);
+ if (ipcp_poly_ctx_values_pool)
+ free_alloc_pool (ipcp_poly_ctx_values_pool);
if (ipcp_agg_lattice_pool)
free_alloc_pool (ipcp_agg_lattice_pool);
if (ipa_refdesc_pool)
===================================================================
@@ -278,13 +278,14 @@ ipa_get_jf_pass_through_agg_preserved (s
return jfunc->value.pass_through.agg_preserved;
}
-/* Return the type_preserved flag of a pass through jump function JFUNC. */
+/* Return true if pass through jump function JFUNC preserves type
+ information. */
static inline bool
ipa_get_jf_pass_through_type_preserved (struct ipa_jump_func *jfunc)
{
gcc_checking_assert (jfunc->type == IPA_JF_PASS_THROUGH);
- return jfunc->value.pass_through.type_preserved;
+ return jfunc->value.pass_through.agg_preserved;
}
/* Return the offset of an ancestor jump function JFUNC. */
@@ -324,13 +325,13 @@ ipa_get_jf_ancestor_agg_preserved (struc
return jfunc->value.ancestor.agg_preserved;
}
-/* Return the type_preserved flag of an ancestor jump function JFUNC. */
+/* Return true if ancestor jump function JFUNC presrves type information. */
static inline bool
ipa_get_jf_ancestor_type_preserved (struct ipa_jump_func *jfunc)
{
gcc_checking_assert (jfunc->type == IPA_JF_ANCESTOR);
- return jfunc->value.ancestor.type_preserved;
+ return jfunc->value.ancestor.agg_preserved;
}
/* Summary describing a single formal parameter. */
@@ -363,9 +364,12 @@ struct ipa_node_params
/* Only for versioned nodes this field would not be NULL,
it points to the node that IPA cp cloned from. */
struct cgraph_node *ipcp_orig_node;
- /* If this node is an ipa-cp clone, these are the known values that describe
- what it has been specialized for. */
- vec<tree> known_vals;
+ /* If this node is an ipa-cp clone, these are the known constants that
+ describe what it has been specialized for. */
+ vec<tree> known_csts;
+ /* If this node is an ipa-cp clone, these are the known polymorphic contexts
+ that describe what it has been specialized for. */
+ vec<ipa_polymorphic_call_context> known_contexts;
/* Whether the param uses analysis and jump function computation has already
been performed. */
unsigned analysis_done : 1;
@@ -592,7 +596,7 @@ bool ipa_propagate_indirect_call_infos (
/* Indirect edge and binfo processing. */
tree ipa_get_indirect_edge_target (struct cgraph_edge *ie,
vec<tree> ,
- vec<tree> ,
+ vec<ipa_polymorphic_call_context>,
vec<ipa_agg_jump_function_p> );
struct cgraph_edge *ipa_make_edge_direct_to_target (struct cgraph_edge *, tree,
bool speculative = false);
@@ -615,7 +619,8 @@ void ipa_print_node_jump_functions (FILE
void ipa_print_all_jump_functions (FILE * f);
void ipcp_verify_propagated_values (void);
-extern alloc_pool ipcp_values_pool;
+extern alloc_pool ipcp_cst_values_pool;
+extern alloc_pool ipcp_poly_ctx_values_pool;
extern alloc_pool ipcp_sources_pool;
extern alloc_pool ipcp_agg_lattice_pool;
@@ -716,6 +721,10 @@ int ipa_get_param_decl_index (struct ipa
tree ipa_value_from_jfunc (struct ipa_node_params *info,
struct ipa_jump_func *jfunc);
unsigned int ipcp_transform_function (struct cgraph_node *node);
+ipa_polymorphic_call_context ipa_context_from_jfunc (ipa_node_params *,
+ cgraph_edge *,
+ int,
+ ipa_jump_func *);
void ipa_dump_param (FILE *, struct ipa_node_params *info, int i);
bool ipa_modify_expr (tree *, bool, ipa_parm_adjustment_vec);
ipa_parm_adjustment *ipa_get_adjustment_candidate (tree **, bool *,
===================================================================
@@ -895,7 +895,8 @@ static void
evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
clause_t *clause_ptr,
vec<tree> *known_vals_ptr,
- vec<tree> *known_binfos_ptr,
+ vec<ipa_polymorphic_call_context>
+ *known_contexts_ptr,
vec<ipa_agg_jump_function_p> *known_aggs_ptr)
{
struct cgraph_node *callee = e->callee->ultimate_alias_target ();
@@ -907,12 +908,12 @@ evaluate_properties_for_edge (struct cgr
*clause_ptr = inline_p ? 0 : 1 << predicate_not_inlined_condition;
if (known_vals_ptr)
known_vals_ptr->create (0);
- if (known_binfos_ptr)
- known_binfos_ptr->create (0);
+ if (known_contexts_ptr)
+ known_contexts_ptr->create (0);
if (ipa_node_params_vector.exists ()
&& !e->call_stmt_cannot_inline_p
- && ((clause_ptr && info->conds) || known_vals_ptr || known_binfos_ptr))
+ && ((clause_ptr && info->conds) || known_vals_ptr || known_contexts_ptr))
{
struct ipa_node_params *parms_info;
struct ipa_edge_args *args = IPA_EDGE_REF (e);
@@ -928,8 +929,8 @@ evaluate_properties_for_edge (struct cgr
known_vals.safe_grow_cleared (count);
if (count && (info->conds || known_aggs_ptr))
known_aggs.safe_grow_cleared (count);
- if (count && known_binfos_ptr)
- known_binfos_ptr->safe_grow_cleared (count);
+ if (count && known_contexts_ptr)
+ known_contexts_ptr->safe_grow_cleared (count);
for (i = 0; i < count; i++)
{
@@ -937,14 +938,16 @@ evaluate_properties_for_edge (struct cgr
tree cst = ipa_value_from_jfunc (parms_info, jf);
if (cst)
{
- if (known_vals.exists () && TREE_CODE (cst) != TREE_BINFO)
+ gcc_checking_assert (TREE_CODE (cst) != TREE_BINFO);
+ if (known_vals.exists ())
known_vals[i] = cst;
- else if (known_binfos_ptr != NULL
- && TREE_CODE (cst) == TREE_BINFO)
- (*known_binfos_ptr)[i] = cst;
}
else if (inline_p && !es->param[i].change_prob)
known_vals[i] = error_mark_node;
+
+ if (known_contexts_ptr)
+ (*known_contexts_ptr)[i] = ipa_context_from_jfunc (parms_info, e,
+ i, jf);
/* TODO: When IPA-CP starts propagating and merging aggregate jump
functions, use its knowledge of the caller too, just like the
scalar case above. */
@@ -2969,14 +2972,14 @@ make_pass_inline_parameters (gcc::contex
}
-/* Estimate benefit devirtualizing indirect edge IE, provided KNOWN_VALS and
- KNOWN_BINFOS. */
+/* Estimate benefit devirtualizing indirect edge IE, provided KNOWN_VALS,
+ KNOWN_CONTEXTS and KNOWN_AGGS. */
static bool
estimate_edge_devirt_benefit (struct cgraph_edge *ie,
int *size, int *time,
vec<tree> known_vals,
- vec<tree> known_binfos,
+ vec<ipa_polymorphic_call_context> known_contexts,
vec<ipa_agg_jump_function_p> known_aggs)
{
tree target;
@@ -2984,12 +2987,12 @@ estimate_edge_devirt_benefit (struct cgr
struct inline_summary *isummary;
enum availability avail;
- if (!known_vals.exists () && !known_binfos.exists ())
+ if (!known_vals.exists () && !known_contexts.exists ())
return false;
if (!flag_indirect_inlining)
return false;
- target = ipa_get_indirect_edge_target (ie, known_vals, known_binfos,
+ target = ipa_get_indirect_edge_target (ie, known_vals, known_contexts,
known_aggs);
if (!target)
return false;
@@ -3013,7 +3016,7 @@ estimate_edge_devirt_benefit (struct cgr
/* Increase SIZE, MIN_SIZE (if non-NULL) and TIME for size and time needed to
handle edge E with probability PROB.
Set HINTS if edge may be devirtualized.
- KNOWN_VALS, KNOWN_AGGS and KNOWN_BINFOS describe context of the call
+ KNOWN_VALS, KNOWN_AGGS and KNOWN_CONTEXTS describe context of the call
site. */
static inline void
@@ -3021,7 +3024,7 @@ estimate_edge_size_and_time (struct cgra
int *time,
int prob,
vec<tree> known_vals,
- vec<tree> known_binfos,
+ vec<ipa_polymorphic_call_context> known_contexts,
vec<ipa_agg_jump_function_p> known_aggs,
inline_hints *hints)
{
@@ -3031,7 +3034,7 @@ estimate_edge_size_and_time (struct cgra
int cur_size;
if (!e->callee
&& estimate_edge_devirt_benefit (e, &call_size, &call_time,
- known_vals, known_binfos, known_aggs)
+ known_vals, known_contexts, known_aggs)
&& hints && e->maybe_hot_p ())
*hints |= INLINE_HINT_indirect_call;
cur_size = call_size * INLINE_SIZE_SCALE;
@@ -3047,9 +3050,8 @@ estimate_edge_size_and_time (struct cgra
/* Increase SIZE, MIN_SIZE and TIME for size and time needed to handle all
- calls in NODE.
- POSSIBLE_TRUTHS, KNOWN_VALS, KNOWN_AGGS and KNOWN_BINFOS describe context of
- the call site. */
+ calls in NODE. POSSIBLE_TRUTHS, KNOWN_VALS, KNOWN_AGGS and KNOWN_CONTEXTS
+ describe context of the call site. */
static void
estimate_calls_size_and_time (struct cgraph_node *node, int *size,
@@ -3057,7 +3059,7 @@ estimate_calls_size_and_time (struct cgr
inline_hints *hints,
clause_t possible_truths,
vec<tree> known_vals,
- vec<tree> known_binfos,
+ vec<ipa_polymorphic_call_context> known_contexts,
vec<ipa_agg_jump_function_p> known_aggs)
{
struct cgraph_edge *e;
@@ -3074,14 +3076,14 @@ estimate_calls_size_and_time (struct cgr
estimate_edge_size_and_time (e, size,
es->predicate ? NULL : min_size,
time, REG_BR_PROB_BASE,
- known_vals, known_binfos,
+ known_vals, known_contexts,
known_aggs, hints);
}
else
estimate_calls_size_and_time (e->callee, size, min_size, time,
hints,
possible_truths,
- known_vals, known_binfos,
+ known_vals, known_contexts,
known_aggs);
}
}
@@ -3093,14 +3095,14 @@ estimate_calls_size_and_time (struct cgr
estimate_edge_size_and_time (e, size,
es->predicate ? NULL : min_size,
time, REG_BR_PROB_BASE,
- known_vals, known_binfos, known_aggs,
+ known_vals, known_contexts, known_aggs,
hints);
}
}
/* Estimate size and time needed to execute NODE assuming
- POSSIBLE_TRUTHS clause, and KNOWN_VALS, KNOWN_AGGS and KNOWN_BINFOS
+ POSSIBLE_TRUTHS clause, and KNOWN_VALS, KNOWN_AGGS and KNOWN_CONTEXTS
information about NODE's arguments. If non-NULL use also probability
information present in INLINE_PARAM_SUMMARY vector.
Additionally detemine hints determined by the context. Finally compute
@@ -3112,7 +3114,7 @@ static void
estimate_node_size_and_time (struct cgraph_node *node,
clause_t possible_truths,
vec<tree> known_vals,
- vec<tree> known_binfos,
+ vec<ipa_polymorphic_call_context> known_contexts,
vec<ipa_agg_jump_function_p> known_aggs,
int *ret_size, int *ret_min_size, int *ret_time,
inline_hints *ret_hints,
@@ -3189,7 +3191,7 @@ estimate_node_size_and_time (struct cgra
hints |= INLINE_HINT_declared_inline;
estimate_calls_size_and_time (node, &size, &min_size, &time, &hints, possible_truths,
- known_vals, known_binfos, known_aggs);
+ known_vals, known_contexts, known_aggs);
gcc_checking_assert (size >= 0);
gcc_checking_assert (time >= 0);
time = RDIV (time, INLINE_TIME_SCALE);
@@ -3212,13 +3214,14 @@ estimate_node_size_and_time (struct cgra
/* Estimate size and time needed to execute callee of EDGE assuming that
parameters known to be constant at caller of EDGE are propagated.
- KNOWN_VALS and KNOWN_BINFOS are vectors of assumed known constant values
+ KNOWN_VALS and KNOWN_CONTEXTS are vectors of assumed known constant values
and types for parameters. */
void
estimate_ipcp_clone_size_and_time (struct cgraph_node *node,
vec<tree> known_vals,
- vec<tree> known_binfos,
+ vec<ipa_polymorphic_call_context>
+ known_contexts,
vec<ipa_agg_jump_function_p> known_aggs,
int *ret_size, int *ret_time,
inline_hints *hints)
@@ -3227,7 +3230,7 @@ estimate_ipcp_clone_size_and_time (struc
clause = evaluate_conditions_for_known_args (node, false, known_vals,
known_aggs);
- estimate_node_size_and_time (node, clause, known_vals, known_binfos,
+ estimate_node_size_and_time (node, clause, known_vals, known_contexts,
known_aggs, ret_size, NULL, ret_time, hints, vNULL);
}
@@ -3672,7 +3675,7 @@ do_estimate_edge_time (struct cgraph_edg
struct cgraph_node *callee;
clause_t clause;
vec<tree> known_vals;
- vec<tree> known_binfos;
+ vec<ipa_polymorphic_call_context> known_contexts;
vec<ipa_agg_jump_function_p> known_aggs;
struct inline_edge_summary *es = inline_edge_summary (edge);
int min_size;
@@ -3681,9 +3684,9 @@ do_estimate_edge_time (struct cgraph_edg
gcc_checking_assert (edge->inline_failed);
evaluate_properties_for_edge (edge, true,
- &clause, &known_vals, &known_binfos,
+ &clause, &known_vals, &known_contexts,
&known_aggs);
- estimate_node_size_and_time (callee, clause, known_vals, known_binfos,
+ estimate_node_size_and_time (callee, clause, known_vals, known_contexts,
known_aggs, &size, &min_size, &time, &hints, es->param);
/* When we have profile feedback, we can quite safely identify hot
@@ -3697,7 +3700,7 @@ do_estimate_edge_time (struct cgraph_edg
hints |= INLINE_HINT_known_hot;
known_vals.release ();
- known_binfos.release ();
+ known_contexts.release ();
known_aggs.release ();
gcc_checking_assert (size >= 0);
gcc_checking_assert (time >= 0);
@@ -3728,7 +3731,7 @@ do_estimate_edge_size (struct cgraph_edg
struct cgraph_node *callee;
clause_t clause;
vec<tree> known_vals;
- vec<tree> known_binfos;
+ vec<ipa_polymorphic_call_context> known_contexts;
vec<ipa_agg_jump_function_p> known_aggs;
/* When we do caching, use do_estimate_edge_time to populate the entry. */
@@ -3746,12 +3749,12 @@ do_estimate_edge_size (struct cgraph_edg
/* Early inliner runs without caching, go ahead and do the dirty work. */
gcc_checking_assert (edge->inline_failed);
evaluate_properties_for_edge (edge, true,
- &clause, &known_vals, &known_binfos,
+ &clause, &known_vals, &known_contexts,
&known_aggs);
- estimate_node_size_and_time (callee, clause, known_vals, known_binfos,
+ estimate_node_size_and_time (callee, clause, known_vals, known_contexts,
known_aggs, &size, NULL, NULL, NULL, vNULL);
known_vals.release ();
- known_binfos.release ();
+ known_contexts.release ();
known_aggs.release ();
return size;
}
@@ -3767,7 +3770,7 @@ do_estimate_edge_hints (struct cgraph_ed
struct cgraph_node *callee;
clause_t clause;
vec<tree> known_vals;
- vec<tree> known_binfos;
+ vec<ipa_polymorphic_call_context> known_contexts;
vec<ipa_agg_jump_function_p> known_aggs;
/* When we do caching, use do_estimate_edge_time to populate the entry. */
@@ -3785,12 +3788,12 @@ do_estimate_edge_hints (struct cgraph_ed
/* Early inliner runs without caching, go ahead and do the dirty work. */
gcc_checking_assert (edge->inline_failed);
evaluate_properties_for_edge (edge, true,
- &clause, &known_vals, &known_binfos,
+ &clause, &known_vals, &known_contexts,
&known_aggs);
- estimate_node_size_and_time (callee, clause, known_vals, known_binfos,
+ estimate_node_size_and_time (callee, clause, known_vals, known_contexts,
known_aggs, NULL, NULL, NULL, &hints, vNULL);
known_vals.release ();
- known_binfos.release ();
+ known_contexts.release ();
known_aggs.release ();
hints |= simple_edge_hints (edge);
return hints;
===================================================================
@@ -223,7 +223,8 @@ void initialize_inline_failed (struct cg
int estimate_time_after_inlining (struct cgraph_node *, struct cgraph_edge *);
int estimate_size_after_inlining (struct cgraph_node *, struct cgraph_edge *);
void estimate_ipcp_clone_size_and_time (struct cgraph_node *,
- vec<tree>, vec<tree>,
+ vec<tree>,
+ vec<ipa_polymorphic_call_context>,
vec<ipa_agg_jump_function_p>,
int *, int *, inline_hints *);
int do_estimate_growth (struct cgraph_node *);
===================================================================
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-options "-O2 -fdump-ipa-inline -fno-devirtualize-speculatively" } */
+/* { dg-options "-O2 -fno-ipa-cp -fdump-ipa-inline -fno-devirtualize-speculatively" } */
int baz ();
struct A
{
@@ -42,7 +42,5 @@ bar ()
baz ();
c + d;
}
-/* While inlining function called once we should devirtualize a new call to fn3.
- Because fn2 is already removed, we should not devirtualize. */
-/* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a known target" 1 "inline" } } */
+/* { dg-final { scan-ipa-dump "Discovered a virtual call to a known target" "inline" } } */
/* { dg-final { cleanup-ipa-dump "inline" } } */
===================================================================
@@ -37,5 +37,5 @@ main()
{
class C c;
}
-/* { dg-final { scan-ipa-dump "Discovered a virtual call to" "cp" { xfail *-*-* } } } */
+/* { dg-final { scan-ipa-dump "Discovered a virtual call to" "cp" } } */
/* { dg-final { cleanup-ipa-dump "cp" } } */
===================================================================
@@ -27,8 +27,6 @@ struct wxBufferedPaintDC : public wxBuf
void OnPaint(wxPaintEvent & event) {
wxBufferedPaintDC dc;
}
-/* IPA-CP should really discover both cases, but for time being the second is handled by inliner. */
-/* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a known target" 1 "inline" } } */
-/* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a known target" 1 "cp" } } */
+/* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a known target" 2 "cp" } } */
/* { dg-final { cleanup-ipa-dump "inline" } } */
/* { dg-final { cleanup-ipa-dump "cp" } } */
===================================================================
@@ -26,6 +26,6 @@ main()
Because the type is in static storage, we know it won't change type in dostuff
and from callstack we can tell that is is not in construction/destruction. */
-/* { dg-final { scan-ipa-dump-times "First type is base of second" 1 "inline" } } */
+/* { dg-final { scan-ipa-dump "Second type is base of first" "inline" } } */
/* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a known target" 1 "inline" } } */
/* { dg-final { cleanup-ipa-dump "inline" } } */
===================================================================
@@ -23,5 +23,5 @@ t(struct B *b)
of type B. This makes A fully specified and we know C::foo is unlikely.
FIXME: We could most probably can devirtualize unconditonally because dereference of b in
&b->a makes the type known. GIMPLE does not represent this. */
-/* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a speculative target" 1 "inline" } } */
+/* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a speculative target" 1 "inline" { xfail *-*-* } } } */
/* { dg-final { cleanup-ipa-dump "inline" } } */
===================================================================
@@ -26,7 +26,7 @@ main()
/* Here one invocation of foo is while type is in construction, while other is not.
Check that we handle that. */
-/* { dg-final { scan-ipa-dump-times "First type is base of second" 1 "inline" } } */
+/* { dg-final { scan-ipa-dump "Second type is base of first" "inline" } } */
/* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a known target\[^\\n\]*A::foo" 1 "inline" } } */
/* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a known target\[^\\n\]*B::foo" 1 "inline" } } */
/* { dg-final { cleanup-ipa-dump "inline" } } */
===================================================================
@@ -1376,9 +1376,12 @@ public:
/* Return TRUE if context is fully useless. */
bool useless_p () const;
+ /* Return TRUE if this context conveys the same information as X. */
+ bool equal_to (const ipa_polymorphic_call_context &x) const;
- /* Dump human readable context to F. */
- void dump (FILE *f) const;
+ /* Dump human readable context to F. If NEWLINE is true, it will be
+ terminated by a newline. */
+ void dump (FILE *f, bool newline = true) const;
void DEBUG_FUNCTION debug () const;
/* LTO streaming. */
===================================================================
@@ -599,10 +599,11 @@ decl_maybe_in_construction_p (tree base,
return false;
}
-/* Dump human readable context to F. */
+/* Dump human readable context to F. If NEWLINE is true, it will be terminated
+ by a newline. */
void
-ipa_polymorphic_call_context::dump (FILE *f) const
+ipa_polymorphic_call_context::dump (FILE *f, bool newline) const
{
fprintf (f, " ");
if (invalid)
@@ -634,7 +635,8 @@ ipa_polymorphic_call_context::dump (FILE
speculative_offset);
}
}
- fprintf(f, "\n");
+ if (newline)
+ fprintf(f, "\n");
}
/* Print context to stderr. */
@@ -2130,3 +2132,47 @@ ipa_polymorphic_call_context::possible_d
else if (in_poly_cdtor)
maybe_in_construction = true;
}
+
+/* Return TRUE if this context conveys the same information as OTHER. */
+
+bool
+ipa_polymorphic_call_context::equal_to
+ (const ipa_polymorphic_call_context &x) const
+{
+ if (useless_p ())
+ return x.useless_p ();
+ if (invalid)
+ return x.invalid;
+ if (x.useless_p () || x.invalid)
+ return false;
+
+ if (outer_type)
+ {
+ if (!x.outer_type
+ || !types_odr_comparable (outer_type, x.outer_type)
+ || !types_same_for_odr (outer_type, x.outer_type)
+ || offset != x.offset
+ || maybe_in_construction != x.maybe_in_construction
+ || maybe_derived_type != x.maybe_derived_type
+ || dynamic != x.dynamic)
+ return false;
+ }
+ else if (x.outer_type)
+ return false;
+
+ if (speculative_outer_type)
+ {
+ if (!x.speculative_outer_type
+ || !types_odr_comparable (speculative_outer_type,
+ x.speculative_outer_type)
+ || !types_same_for_odr (speculative_outer_type,
+ x.speculative_outer_type)
+ || speculative_offset != x.speculative_offset
+ || speculative_maybe_derived_type != x.speculative_maybe_derived_type)
+ return false;
+ }
+ else if (x.speculative_outer_type)
+ return false;
+
+ return true;
+}
===================================================================
@@ -36,7 +36,7 @@ C *b = new (C);
sort(f, *b);
}
}
-/* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a known target" 1 "inline" } } */
+/* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a known target" 1 "inline" { xfail *-*-* } } } */
/* { dg-final { cleanup-ipa-dump "inline" } } */
/* { dg-final { scan-ipa-dump-times "Aggregate passed by reference" 1 "cp" } } */
/* { dg-final { cleanup-ipa-dump "cp" } } */