aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJan Hubicka <hubicka@ucw.cz>2014-11-16 22:01:45 +0100
committerJan Hubicka <hubicka@gcc.gnu.org>2014-11-16 21:01:45 +0000
commitdf0d8136f133fe11790812caee0712f37c0ae5d9 (patch)
treeb591fcf9084565e571a8a71a0b47d8f967b437ee /gcc
parent70486010428fdaeabd875022fee05122e9866424 (diff)
downloadgcc-df0d8136f133fe11790812caee0712f37c0ae5d9.zip
gcc-df0d8136f133fe11790812caee0712f37c0ae5d9.tar.gz
gcc-df0d8136f133fe11790812caee0712f37c0ae5d9.tar.bz2
* 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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog20
-rw-r--r--gcc/cgraph.h4
-rw-r--r--gcc/ipa-cp.c69
-rw-r--r--gcc/ipa-polymorphic-call.c321
4 files changed, 375 insertions, 39 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index d035fe15..d385e33 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,25 @@
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
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 77c2a60..fc5fe82 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.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);
};
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index 0529f17..375b49e 100644
--- a/gcc/ipa-cp.c
+++ b/gcc/ipa-cp.c
@@ -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 ();
- }
+ edge_ctx = *edge_ctx_ptr;
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 ())
- cur.combine_with (edge_ctx);
+ /* 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))
{
diff --git a/gcc/ipa-polymorphic-call.c b/gcc/ipa-polymorphic-call.c
index f1905f1..452f2d2 100644
--- a/gcc/ipa-polymorphic-call.c
+++ b/gcc/ipa-polymorphic-call.c
@@ -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,19 +2266,220 @@ 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,
- x.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)
+ 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)
+ 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;
+}