Commit df0d8136 by Jan Hubicka Committed by Jan Hubicka

* ipa-polymorphic-call.c

	(ipa_polymorphic_call_context::speculation_consistent_p): Constify.
	(ipa_polymorphic_call_context::meet_speculation_with): New function.
	(ipa_polymorphic_call_context::combine_with): Handle types in construction
	better.
	(ipa_polymorphic_call_context::equal_to): Do not bother about useless
	speculation.
	(ipa_polymorphic_call_context::meet_with): New function.
	* cgraph.h (class ipa_polymorphic_call_context): Add
	meet_width, meet_speculation_with; constify speculation_consistent_p.
	* ipa-cp.c (ipa_context_from_jfunc): Handle speculation; combine with incomming
	context.
	(propagate_context_accross_jump_function): Likewise; be more cureful.
	about set_contains_variable.
	(ipa_get_indirect_edge_target_1): Fix handling of dynamic type changes.
	(find_more_scalar_values_for_callers_subset): Fix.
	(find_more_contexts_for_caller_subset): Perform meet operation.

From-SVN: r217634
parent 70486010
2014-11-16 Jan Hubicka <hubicka@ucw.cz>
* ipa-polymorphic-call.c
(ipa_polymorphic_call_context::speculation_consistent_p): Constify.
(ipa_polymorphic_call_context::meet_speculation_with): New function.
(ipa_polymorphic_call_context::combine_with): Handle types in construction
better.
(ipa_polymorphic_call_context::equal_to): Do not bother about useless
speculation.
(ipa_polymorphic_call_context::meet_with): New function.
* cgraph.h (class ipa_polymorphic_call_context): Add
meet_width, meet_speculation_with; constify speculation_consistent_p.
* ipa-cp.c (ipa_context_from_jfunc): Handle speculation; combine with incomming
context.
(propagate_context_accross_jump_function): Likewise; be more cureful.
about set_contains_variable.
(ipa_get_indirect_edge_target_1): Fix handling of dynamic type changes.
(find_more_scalar_values_for_callers_subset): Fix.
(find_more_contexts_for_caller_subset): Perform meet operation.
2014-11-16 Jan Hubicka <hubicka@ucw.cz>
* passes.c (execute_one_pass): Do not apply all transforms prior
every simple IPA pass.
* cgraphunit.c: Do not include fibheap.h
......@@ -1389,6 +1389,7 @@ public:
If actual type the context is being used in is known, OTR_TYPE should be
set accordingly. This improves quality of combined result. */
bool combine_with (ipa_polymorphic_call_context, tree otr_type = NULL);
bool meet_with (ipa_polymorphic_call_context, tree otr_type = NULL);
/* Return TRUE if context is fully useless. */
bool useless_p () const;
......@@ -1406,9 +1407,10 @@ public:
private:
bool combine_speculation_with (tree, HOST_WIDE_INT, bool, tree);
bool meet_speculation_with (tree, HOST_WIDE_INT, bool, tree);
void set_by_decl (tree, HOST_WIDE_INT);
bool set_by_invariant (tree, tree, HOST_WIDE_INT);
bool speculation_consistent_p (tree, HOST_WIDE_INT, bool, tree);
bool speculation_consistent_p (tree, HOST_WIDE_INT, bool, tree) const;
void make_speculative (tree otr_type = NULL);
};
......
......@@ -946,17 +946,17 @@ ipa_context_from_jfunc (ipa_node_params *info, cgraph_edge *cs, int csidx,
{
ipa_polymorphic_call_context srcctx;
int srcidx;
bool type_preserved = true;
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))
if (ipa_get_jf_pass_through_operation (jfunc) != NOP_EXPR)
return ctx;
type_preserved = ipa_get_jf_pass_through_type_preserved (jfunc);
srcidx = ipa_get_jf_pass_through_formal_id (jfunc);
}
else
{
if (!ipa_get_jf_ancestor_type_preserved (jfunc))
return ctx;
type_preserved = ipa_get_jf_ancestor_type_preserved (jfunc);
srcidx = ipa_get_jf_ancestor_formal_id (jfunc);
}
if (info->ipcp_orig_node)
......@@ -981,7 +981,10 @@ ipa_context_from_jfunc (ipa_node_params *info, cgraph_edge *cs, int csidx,
return ctx;
if (jfunc->type == IPA_JF_ANCESTOR)
srcctx.offset_by (ipa_get_jf_ancestor_offset (jfunc));
ctx.combine_with (srcctx);
if (!type_preserved)
srcctx.possible_dynamic_type_change (cs->in_polymorphic_cdtor);
srcctx.combine_with (ctx);
return srcctx;
}
return ctx;
......@@ -1298,15 +1301,13 @@ propagate_context_accross_jump_function (cgraph_edge *cs,
return false;
bool ret = false;
bool added_sth = false;
bool type_preserved = true;
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)
......@@ -1320,15 +1321,14 @@ propagate_context_accross_jump_function (cgraph_edge *cs,
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))
if (ipa_get_jf_pass_through_operation (jfunc) != NOP_EXPR)
goto prop_fail;
type_preserved = ipa_get_jf_pass_through_type_preserved (jfunc);
src_idx = ipa_get_jf_pass_through_formal_id (jfunc);
}
else
{
if (!ipa_get_jf_ancestor_type_preserved (jfunc))
goto prop_fail;
type_preserved = ipa_get_jf_ancestor_type_preserved (jfunc);
src_idx = ipa_get_jf_ancestor_formal_id (jfunc);
}
......@@ -1338,21 +1338,24 @@ propagate_context_accross_jump_function (cgraph_edge *cs,
&& (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 (!type_preserved)
cur.possible_dynamic_type_change (cs->in_polymorphic_cdtor);
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 ())
/* TODO: In cases we know how the context is going to be used,
we can improve the result by passing proper OTR_TYPE. */
cur.combine_with (edge_ctx);
if (!cur.useless_p ())
{
if (src_lat->contains_variable
&& !edge_ctx.equal_to (cur))
ret |= dest_lat->set_contains_variable ();
ret |= dest_lat->add_value (cur, cs, src_val, src_idx);
added_sth = true;
}
......@@ -1848,6 +1851,10 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
if (known_contexts.length () > (unsigned int) param_index)
{
context = known_contexts[param_index];
context.offset_by (anc_offset);
if (ie->indirect_info->vptr_changed)
context.possible_dynamic_type_change (ie->in_polymorphic_cdtor,
ie->indirect_info->otr_type);
if (t)
{
ipa_polymorphic_call_context ctx2 = ipa_polymorphic_call_context
......@@ -3160,6 +3167,7 @@ find_more_scalar_values_for_callers_subset (struct cgraph_node *node,
struct cgraph_edge *cs;
tree newval = NULL_TREE;
int j;
bool first = true;
if (ipa_get_scalar_lat (info, i)->bottom || known_csts[i])
continue;
......@@ -3178,13 +3186,15 @@ find_more_scalar_values_for_callers_subset (struct cgraph_node *node,
t = ipa_value_from_jfunc (IPA_NODE_REF (cs->caller), jump_func);
if (!t
|| (newval
&& !values_equal_for_ipcp_p (t, newval)))
&& !values_equal_for_ipcp_p (t, newval))
|| (!first && !newval))
{
newval = NULL_TREE;
break;
}
else
newval = t;
first = false;
}
if (newval)
......@@ -3226,7 +3236,7 @@ find_more_contexts_for_caller_subset (cgraph_node *node,
continue;
ipa_polymorphic_call_context newval;
bool found = false;
bool first = true;
int j;
FOR_EACH_VEC_ELT (callers, j, cs)
......@@ -3238,21 +3248,18 @@ find_more_contexts_for_caller_subset (cgraph_node *node,
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)
if (first)
{
found = true;
newval = ctx;
first = false;
}
else
newval.meet_with (ctx);
if (newval.useless_p ())
break;
}
if (found)
if (!newval.useless_p ())
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
......
......@@ -1727,7 +1727,7 @@ bool
ipa_polymorphic_call_context::speculation_consistent_p (tree spec_outer_type,
HOST_WIDE_INT spec_offset,
bool spec_maybe_derived_type,
tree otr_type)
tree otr_type) const
{
if (!flag_devirtualize_speculatively)
return false;
......@@ -1873,6 +1873,102 @@ ipa_polymorphic_call_context::combine_speculation_with
return false;
}
/* Make speculation less specific so
NEW_OUTER_TYPE, NEW_OFFSET, NEW_MAYBE_DERIVED_TYPE is also included.
If OTR_TYPE is set, assume the context is used with OTR_TYPE. */
bool
ipa_polymorphic_call_context::meet_speculation_with
(tree new_outer_type, HOST_WIDE_INT new_offset, bool new_maybe_derived_type,
tree otr_type)
{
if (!new_outer_type && speculative_outer_type)
{
clear_speculation ();
return true;
}
/* restrict_to_inner_class may eliminate wrong speculation making our job
easeier. */
if (otr_type)
restrict_to_inner_class (otr_type);
if (!speculative_outer_type
|| !speculation_consistent_p (speculative_outer_type,
speculative_offset,
speculative_maybe_derived_type,
otr_type))
return false;
if (!speculation_consistent_p (new_outer_type, new_offset,
new_maybe_derived_type, otr_type))
{
clear_speculation ();
return true;
}
else if (types_must_be_same_for_odr (speculative_outer_type,
new_outer_type))
{
if (speculative_offset != new_offset)
{
clear_speculation ();
return true;
}
else
{
if (!speculative_maybe_derived_type && new_maybe_derived_type)
{
speculative_maybe_derived_type = true;
return true;
}
else
return false;
}
}
/* See if one type contains the other as a field (not base). */
else if (contains_type_p (new_outer_type, new_offset - speculative_offset,
speculative_outer_type, false, false))
return false;
else if (contains_type_p (speculative_outer_type,
speculative_offset - new_offset,
new_outer_type, false, false))
{
speculative_outer_type = new_outer_type;
speculative_offset = new_offset;
speculative_maybe_derived_type = new_maybe_derived_type;
return true;
}
/* See if OUTER_TYPE is base of CTX.OUTER_TYPE. */
else if (contains_type_p (new_outer_type,
new_offset - speculative_offset,
speculative_outer_type, false, true))
{
if (!speculative_maybe_derived_type)
{
speculative_maybe_derived_type = true;
return true;
}
return false;
}
/* See if CTX.OUTER_TYPE is base of OUTER_TYPE. */
else if (contains_type_p (speculative_outer_type,
speculative_offset - new_offset, new_outer_type, false, true))
{
speculative_outer_type = new_outer_type;
speculative_offset = new_offset;
speculative_maybe_derived_type = true;
return true;
}
else
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Giving up on speculative meet\n");
clear_speculation ();
return true;
}
}
/* Assume that both THIS and a given context is valid and strenghten THIS
if possible. Return true if any strenghtening was made.
If actual type the context is being used in is known, OTR_TYPE should be
......@@ -2065,6 +2161,16 @@ ipa_polymorphic_call_context::combine_with (ipa_polymorphic_call_context ctx,
fprintf (dump_file, "First context does not permit base -> invalid\n");
goto invalidate;
}
/* Pick the base type. */
else if (maybe_in_construction)
{
outer_type = ctx.outer_type;
maybe_in_construction = ctx.maybe_in_construction;
maybe_derived_type = ctx.maybe_derived_type;
offset = ctx.offset;
dynamic = ctx.dynamic;
updated = true;
}
}
}
/* TODO handle merging using hiearchy. */
......@@ -2160,10 +2266,15 @@ ipa_polymorphic_call_context::equal_to
else if (x.outer_type)
return false;
if (speculative_outer_type)
if (speculative_outer_type
&& speculation_consistent_p (speculative_outer_type, speculative_offset,
speculative_maybe_derived_type, NULL_TREE))
{
if (!x.speculative_outer_type
|| !types_odr_comparable (speculative_outer_type,
if (!x.speculative_outer_type)
return false;
if (!types_odr_comparable (speculative_outer_type,
x.speculative_outer_type)
|| !types_same_for_odr (speculative_outer_type,
x.speculative_outer_type)
......@@ -2171,8 +2282,204 @@ ipa_polymorphic_call_context::equal_to
|| speculative_maybe_derived_type != x.speculative_maybe_derived_type)
return false;
}
else if (x.speculative_outer_type)
else if (x.speculative_outer_type
&& x.speculation_consistent_p (x.speculative_outer_type,
x.speculative_offset,
x.speculative_maybe_derived_type,
NULL))
return false;
return true;
}
/* Modify context to be strictly less restrictive than CTX. */
bool
ipa_polymorphic_call_context::meet_with (ipa_polymorphic_call_context ctx,
tree otr_type)
{
bool updated = false;
if (useless_p () || ctx.invalid)
return false;
/* Restricting context to inner type makes merging easier, however do not
do that unless we know how the context is used (OTR_TYPE is non-NULL) */
if (otr_type && !useless_p () && !ctx.useless_p ())
{
restrict_to_inner_class (otr_type);
ctx.restrict_to_inner_class (otr_type);
if(invalid)
return false;
}
if (equal_to (ctx))
return false;
if (ctx.useless_p () || invalid)
{
*this = ctx;
return true;
}
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "Polymorphic call context meet:");
dump (dump_file);
fprintf (dump_file, "With context: ");
ctx.dump (dump_file);
if (otr_type)
{
fprintf (dump_file, "To be used with type: ");
print_generic_expr (dump_file, otr_type, TDF_SLIM);
fprintf (dump_file, "\n");
}
}
if (!dynamic && ctx.dynamic)
{
dynamic = true;
updated = true;
}
/* If call is known to be invalid, we are done. */
if (!outer_type)
;
else if (!ctx.outer_type)
{
clear_outer_type ();
updated = true;
}
/* If types are known to be same, merging is quite easy. */
else if (types_must_be_same_for_odr (outer_type, ctx.outer_type))
{
if (offset != ctx.offset
&& TYPE_SIZE (outer_type)
&& TREE_CODE (TYPE_SIZE (outer_type)) == INTEGER_CST)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Outer types match, offset mismatch -> clearing\n");
clear_outer_type ();
return true;
}
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Outer types match, merging flags\n");
if (!maybe_in_construction && ctx.maybe_in_construction)
{
updated = true;
maybe_in_construction = true;
}
if (!maybe_derived_type && ctx.maybe_derived_type)
{
updated = true;
maybe_derived_type = true;
}
if (!dynamic && ctx.dynamic)
{
updated = true;
dynamic = true;
}
}
/* See if one type contains the other as a field (not base). */
else if (contains_type_p (ctx.outer_type, ctx.offset - offset,
outer_type, false, false))
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Second type contain the first as a field\n");
/* The second type is more specified, so we keep the first.
We need to set DYNAMIC flag to avoid declaring context INVALID
of OFFSET ends up being out of range. */
if (!dynamic
&& (ctx.dynamic
|| (!otr_type
&& (!TYPE_SIZE (ctx.outer_type)
|| !TYPE_SIZE (outer_type)
|| !operand_equal_p (TYPE_SIZE (ctx.outer_type),
TYPE_SIZE (outer_type), 0)))))
{
dynamic = true;
updated = true;
}
}
else if (contains_type_p (outer_type, offset - ctx.offset,
ctx.outer_type, false, false))
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "First type contain the second as a field\n");
if (!dynamic
&& (ctx.dynamic
|| (!otr_type
&& (!TYPE_SIZE (ctx.outer_type)
|| !TYPE_SIZE (outer_type)
|| !operand_equal_p (TYPE_SIZE (ctx.outer_type),
TYPE_SIZE (outer_type), 0)))))
dynamic = true;
outer_type = ctx.outer_type;
offset = ctx.offset;
dynamic = ctx.dynamic;
maybe_in_construction = ctx.maybe_in_construction;
maybe_derived_type = ctx.maybe_derived_type;
updated = true;
}
/* See if OUTER_TYPE is base of CTX.OUTER_TYPE. */
else if (contains_type_p (ctx.outer_type,
ctx.offset - offset, outer_type, false, true))
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "First type is base of second\n");
if (!maybe_derived_type)
{
maybe_derived_type = true;
updated = true;
}
if (!maybe_in_construction && ctx.maybe_in_construction)
{
maybe_in_construction = true;
updated = true;
}
if (!dynamic && ctx.dynamic)
{
dynamic = true;
updated = true;
}
}
/* See if CTX.OUTER_TYPE is base of OUTER_TYPE. */
else if (contains_type_p (outer_type,
offset - ctx.offset, ctx.outer_type, false, true))
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Second type is base of first\n");
outer_type = ctx.outer_type;
offset = ctx.offset;
updated = true;
if (!maybe_derived_type)
maybe_derived_type = true;
if (!maybe_in_construction && ctx.maybe_in_construction)
maybe_in_construction = true;
if (!dynamic && ctx.dynamic)
dynamic = true;
}
/* TODO handle merging using hiearchy. */
else
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Giving up on meet\n");
clear_outer_type ();
updated = true;
}
updated |= meet_speculation_with (ctx.speculative_outer_type,
ctx.speculative_offset,
ctx.speculative_maybe_derived_type,
otr_type);
if (updated && dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "Updated as: ");
dump (dump_file);
fprintf (dump_file, "\n");
}
return updated;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment