ipa-utils.h (polymorphic_call_context): Add metdhos dump, debug and clear_outer_type.
* ipa-utils.h (polymorphic_call_context): Add metdhos dump, debug and clear_outer_type. (ipa_polymorphic_call_context::ipa_polymorphic_call_context): Simplify. (ipa_polymorphic_call_context::clear_outer_type): New method. * ipa-prop.c (ipa_analyze_call_uses): Do not overwrite offset. * ipa-devirt.c (types_odr_comparable): New function. (types_must_be_same_for_odr): New function. (odr_subtypes_equivalent_p): Simplify. (possible_placement_new): Break out from ... (ipa_polymorphic_call_context::restrict_to_inner_type): ... here; be more cuatious about returning false in cases the context may be valid in derived type or via placement new. (contains_type_p): Clear maybe_derived_type (ipa_polymorphic_call_context::dump): New method. (ipa_polymorphic_call_context::debug): New method. (ipa_polymorphic_call_context::set_by_decl): Cleanup comment. (ipa_polymorphic_call_context::set_by_invariant): Simplify. (ipa_polymorphic_call_context::ipa_polymorphic_call_context): Simplify. (possible_polymorphic_call_targets): Trust context.restrict_to_inner_class to suceed on all valid cases; remove confused sanity check. (dump_possible_polymorphic_call_targets): Simplify. From-SVN: r215569
This commit is contained in:
parent
c6195f588b
commit
a198145843
@ -1,3 +1,27 @@
|
||||
2014-09-24 Jan Hubicka <hubicka@ucw.cz>
|
||||
|
||||
* ipa-utils.h (polymorphic_call_context): Add
|
||||
metdhos dump, debug and clear_outer_type.
|
||||
(ipa_polymorphic_call_context::ipa_polymorphic_call_context): Simplify.
|
||||
(ipa_polymorphic_call_context::clear_outer_type): New method.
|
||||
* ipa-prop.c (ipa_analyze_call_uses): Do not overwrite offset.
|
||||
* ipa-devirt.c (types_odr_comparable): New function.
|
||||
(types_must_be_same_for_odr): New function.
|
||||
(odr_subtypes_equivalent_p): Simplify.
|
||||
(possible_placement_new): Break out from ...
|
||||
(ipa_polymorphic_call_context::restrict_to_inner_type): ... here;
|
||||
be more cuatious about returning false in cases the context may be
|
||||
valid in derived type or via placement new.
|
||||
(contains_type_p): Clear maybe_derived_type
|
||||
(ipa_polymorphic_call_context::dump): New method.
|
||||
(ipa_polymorphic_call_context::debug): New method.
|
||||
(ipa_polymorphic_call_context::set_by_decl): Cleanup comment.
|
||||
(ipa_polymorphic_call_context::set_by_invariant): Simplify.
|
||||
(ipa_polymorphic_call_context::ipa_polymorphic_call_context): Simplify.
|
||||
(possible_polymorphic_call_targets): Trust context.restrict_to_inner_class
|
||||
to suceed on all valid cases; remove confused sanity check.
|
||||
(dump_possible_polymorphic_call_targets): Simplify.
|
||||
|
||||
2014-09-24 Aldy Hernandez <aldyh@redhat.com>
|
||||
|
||||
* cgraph.h, dbxout.c, dwarfout2.c, gimple-fold.c,
|
||||
|
380
gcc/ipa-devirt.c
380
gcc/ipa-devirt.c
@ -452,6 +452,34 @@ types_same_for_odr (const_tree type1, const_tree type2)
|
||||
== DECL_ASSEMBLER_NAME (TYPE_NAME (type2)));
|
||||
}
|
||||
|
||||
/* Return true if we can decide on ODR equivalency.
|
||||
|
||||
In non-LTO it is always decide, in LTO however it depends in the type has
|
||||
ODR info attached. */
|
||||
|
||||
static bool
|
||||
types_odr_comparable (tree t1, tree t2)
|
||||
{
|
||||
return (!in_lto_p
|
||||
|| main_odr_variant (t1) == main_odr_variant (t2)
|
||||
|| (odr_type_p (t1) && odr_type_p (t2))
|
||||
|| (TREE_CODE (t1) == RECORD_TYPE && TREE_CODE (t2) == RECORD_TYPE
|
||||
&& TYPE_BINFO (t1) && TYPE_BINFO (t2)
|
||||
&& polymorphic_type_binfo_p (TYPE_BINFO (t1))
|
||||
&& polymorphic_type_binfo_p (TYPE_BINFO (t2))));
|
||||
}
|
||||
|
||||
/* Return true if T1 and T2 are ODR equivalent. If ODR equivalency is not
|
||||
known, be conservative and return false. */
|
||||
|
||||
static bool
|
||||
types_must_be_same_for_odr (tree t1, tree t2)
|
||||
{
|
||||
if (types_odr_comparable (t1, t2))
|
||||
return types_same_for_odr (t1, t2);
|
||||
else
|
||||
return main_odr_variant (t1) == main_odr_variant (t2);
|
||||
}
|
||||
|
||||
/* Compare types T1 and T2 and return true if they are
|
||||
equivalent. */
|
||||
@ -528,11 +556,7 @@ odr_subtypes_equivalent_p (tree t1, tree t2, hash_set<type_pair,pair_traits> *vi
|
||||
/* For ODR types be sure to compare their names.
|
||||
To support -wno-odr-type-merging we allow one type to be non-ODR
|
||||
and other ODR even though it is a violation. */
|
||||
if ((odr_type_p (t1) && odr_type_p (t2))
|
||||
|| (TREE_CODE (t1) == RECORD_TYPE && TREE_CODE (t2) == RECORD_TYPE
|
||||
&& TYPE_BINFO (t1) && TYPE_BINFO (t2)
|
||||
&& polymorphic_type_binfo_p (TYPE_BINFO (t1))
|
||||
&& polymorphic_type_binfo_p (TYPE_BINFO (t2))))
|
||||
if (types_odr_comparable (t1, t2))
|
||||
{
|
||||
if (!types_same_for_odr (t1, t2))
|
||||
return false;
|
||||
@ -1325,8 +1349,8 @@ get_odr_type (tree type, bool insert)
|
||||
type = main_odr_variant (type);
|
||||
|
||||
hash = hash_type_name (type);
|
||||
slot
|
||||
= odr_hash->find_slot_with_hash (type, hash, insert ? INSERT : NO_INSERT);
|
||||
slot = odr_hash->find_slot_with_hash (type, hash,
|
||||
insert ? INSERT : NO_INSERT);
|
||||
if (!slot)
|
||||
return NULL;
|
||||
|
||||
@ -1979,12 +2003,37 @@ contains_polymorphic_type_p (const_tree type)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Return true if it seems valid to use placement new to build EXPECTED_TYPE
|
||||
at possition CUR_OFFSET within TYPE.
|
||||
|
||||
POD can be changed to an instance of a polymorphic type by
|
||||
placement new. Here we play safe and assume that any
|
||||
non-polymorphic type is POD. */
|
||||
bool
|
||||
possible_placement_new (tree type, tree expected_type,
|
||||
HOST_WIDE_INT cur_offset)
|
||||
{
|
||||
return ((TREE_CODE (type) != RECORD_TYPE
|
||||
|| !TYPE_BINFO (type)
|
||||
|| cur_offset >= BITS_PER_WORD
|
||||
|| !polymorphic_type_binfo_p (TYPE_BINFO (type)))
|
||||
&& (!TYPE_SIZE (type)
|
||||
|| !tree_fits_shwi_p (TYPE_SIZE (type))
|
||||
|| (cur_offset
|
||||
+ (expected_type ? tree_to_uhwi (TYPE_SIZE (expected_type))
|
||||
: 1)
|
||||
<= tree_to_uhwi (TYPE_SIZE (type)))));
|
||||
}
|
||||
|
||||
/* THIS->OUTER_TYPE is a type of memory object where object of EXPECTED_TYPE
|
||||
is contained at THIS->OFFSET. Walk the memory representation of
|
||||
THIS->OUTER_TYPE and find the outermost class type that match
|
||||
EXPECTED_TYPE or contain EXPECTED_TYPE as a base. Update THIS
|
||||
to represent it.
|
||||
|
||||
If EXPECTED_TYPE is NULL, just find outermost polymorphic type with
|
||||
virtual table present at possition OFFSET.
|
||||
|
||||
For example when THIS represents type
|
||||
class A
|
||||
{
|
||||
@ -2005,69 +2054,111 @@ ipa_polymorphic_call_context::restrict_to_inner_class (tree expected_type)
|
||||
tree type = outer_type;
|
||||
HOST_WIDE_INT cur_offset = offset;
|
||||
bool speculative = false;
|
||||
bool speculation_valid = false;
|
||||
bool valid = false;
|
||||
|
||||
/* Update OUTER_TYPE to match EXPECTED_TYPE if it is not set. */
|
||||
if (!outer_type)
|
||||
{
|
||||
type = outer_type = expected_type;
|
||||
offset = cur_offset = 0;
|
||||
clear_outer_type (expected_type);
|
||||
type = expected_type;
|
||||
cur_offset = 0;
|
||||
}
|
||||
/* See if OFFSET points inside OUTER_TYPE. If it does not, we know
|
||||
that the context is either invalid, or the instance type must be
|
||||
derived from OUTER_TYPE.
|
||||
|
||||
if (speculative_outer_type == outer_type
|
||||
&& (!maybe_derived_type
|
||||
|| speculative_maybe_derived_type))
|
||||
Because the instance type may contain field whose type is of OUTER_TYPE,
|
||||
we can not derive any effective information about it.
|
||||
|
||||
TODO: In the case we know all derrived types, we can definitely do better
|
||||
here. */
|
||||
else if (TYPE_SIZE (outer_type)
|
||||
&& tree_fits_shwi_p (TYPE_SIZE (outer_type))
|
||||
&& tree_to_shwi (TYPE_SIZE (outer_type)) >= 0
|
||||
&& tree_to_shwi (TYPE_SIZE (outer_type)) <= offset)
|
||||
{
|
||||
speculative_outer_type = NULL;
|
||||
speculative_offset = 0;
|
||||
speculative_maybe_derived_type = false;
|
||||
clear_outer_type (expected_type);
|
||||
type = expected_type;
|
||||
cur_offset = 0;
|
||||
|
||||
/* If derived type is not allowed, we know that the context is invalid. */
|
||||
if (!maybe_derived_type)
|
||||
{
|
||||
clear_speculation ();
|
||||
invalid = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* See if speculative type seem to be derrived from outer_type.
|
||||
Then speculation is valid only if it really is a derivate and derived types
|
||||
are allowed.
|
||||
if (speculative_outer_type)
|
||||
{
|
||||
/* Short cirucit the busy work bellow and give up on case when speculation
|
||||
is obviously the same as outer_type. */
|
||||
if ((!maybe_derived_type
|
||||
|| speculative_maybe_derived_type)
|
||||
&& types_must_be_same_for_odr (speculative_outer_type, outer_type))
|
||||
clear_speculation ();
|
||||
|
||||
The test does not really look for derivate, but also accepts the case where
|
||||
outer_type is a field of speculative_outer_type. In this case eiter
|
||||
MAYBE_DERIVED_TYPE is false and we have full non-speculative information or
|
||||
the loop bellow will correctly update SPECULATIVE_OUTER_TYPE
|
||||
and SPECULATIVE_MAYBE_DERIVED_TYPE. */
|
||||
if (speculative_outer_type
|
||||
&& speculative_offset >= offset
|
||||
&& contains_type_p (speculative_outer_type,
|
||||
offset - speculative_offset,
|
||||
outer_type))
|
||||
speculation_valid = maybe_derived_type;
|
||||
/* See if SPECULATIVE_OUTER_TYPE is contained in or derived from OUTER_TYPE.
|
||||
In this case speculation is valid only if derived types are allowed.
|
||||
|
||||
The test does not really look for derivate, but also accepts the case where
|
||||
outer_type is a field of speculative_outer_type. In this case eiter
|
||||
MAYBE_DERIVED_TYPE is false and we have full non-speculative information or
|
||||
the loop bellow will correctly update SPECULATIVE_OUTER_TYPE
|
||||
and SPECULATIVE_MAYBE_DERIVED_TYPE. */
|
||||
else if (speculative_offset < offset
|
||||
|| !contains_type_p (speculative_outer_type,
|
||||
speculative_offset - offset,
|
||||
outer_type)
|
||||
|| !maybe_derived_type)
|
||||
clear_speculation ();
|
||||
}
|
||||
else
|
||||
/* Regularize things little bit and clear all the fields when no useful
|
||||
speculatin is known. */
|
||||
clear_speculation ();
|
||||
|
||||
|
||||
if (!type)
|
||||
goto no_useful_type_info;
|
||||
|
||||
/* Find the sub-object the constant actually refers to and mark whether it is
|
||||
an artificial one (as opposed to a user-defined one).
|
||||
|
||||
This loop is performed twice; first time for outer_type and second time
|
||||
for speculative_outer_type. The second iteration has SPECULATIVE set. */
|
||||
for speculative_outer_type. The second run has SPECULATIVE set. */
|
||||
while (true)
|
||||
{
|
||||
HOST_WIDE_INT pos, size;
|
||||
tree fld;
|
||||
bool size_unknown;
|
||||
|
||||
/* If we do not know size of TYPE, we need to be more conservative
|
||||
about accepting cases where we can not find EXPECTED_TYPE.
|
||||
Generally the types that do matter here are of constant size.
|
||||
Size_unknown case should be very rare. */
|
||||
if (TYPE_SIZE (type)
|
||||
&& tree_fits_shwi_p (TYPE_SIZE (type))
|
||||
&& tree_to_shwi (TYPE_SIZE (type)) >= 0)
|
||||
size_unknown = false;
|
||||
else
|
||||
size_unknown = true;
|
||||
|
||||
/* On a match, just return what we found. */
|
||||
if (TREE_CODE (type) == TREE_CODE (expected_type)
|
||||
&& (!in_lto_p
|
||||
|| (TREE_CODE (type) == RECORD_TYPE
|
||||
&& TYPE_BINFO (type)
|
||||
&& polymorphic_type_binfo_p (TYPE_BINFO (type))))
|
||||
&& types_same_for_odr (type, expected_type))
|
||||
if ((types_odr_comparable (type, expected_type)
|
||||
&& types_same_for_odr (type, expected_type))
|
||||
|| (!expected_type
|
||||
&& TREE_CODE (type) == RECORD_TYPE
|
||||
&& TYPE_BINFO (type)
|
||||
&& polymorphic_type_binfo_p (TYPE_BINFO (type))))
|
||||
{
|
||||
if (speculative)
|
||||
{
|
||||
gcc_assert (speculation_valid);
|
||||
gcc_assert (valid);
|
||||
|
||||
/* If we did not match the offset, just give up on speculation. */
|
||||
if (cur_offset != 0
|
||||
|| (types_same_for_odr (speculative_outer_type,
|
||||
outer_type)
|
||||
/* Also check if speculation did not end up being same as
|
||||
non-speculation. */
|
||||
|| (types_must_be_same_for_odr (speculative_outer_type,
|
||||
outer_type)
|
||||
&& (maybe_derived_type
|
||||
== speculative_maybe_derived_type)))
|
||||
clear_speculation ();
|
||||
@ -2075,18 +2166,24 @@ ipa_polymorphic_call_context::restrict_to_inner_class (tree expected_type)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If type is known to be final, do not worry about derived
|
||||
types. Testing it here may help us to avoid speculation. */
|
||||
if (type_all_derivations_known_p (outer_type)
|
||||
&& (TYPE_FINAL_P (outer_type)
|
||||
|| (odr_hash
|
||||
&& !get_odr_type (outer_type, true)->derived_types.length())))
|
||||
maybe_derived_type = false;
|
||||
|
||||
/* Type can not contain itself on an non-zero offset. In that case
|
||||
just give up. */
|
||||
just give up. Still accept the case where size is now known.
|
||||
Either the second copy may appear past the end of type or within
|
||||
the non-POD buffer located inside the variably sized type
|
||||
itself. */
|
||||
if (cur_offset != 0)
|
||||
{
|
||||
valid = false;
|
||||
goto give_up;
|
||||
}
|
||||
valid = true;
|
||||
/* If speculation is not valid or we determined type precisely,
|
||||
we are done. */
|
||||
if (!speculation_valid
|
||||
|| !maybe_derived_type)
|
||||
goto no_useful_type_info;
|
||||
/* If we determined type precisely or we have no clue on
|
||||
speuclation, we are done. */
|
||||
if (!maybe_derived_type || !speculative_outer_type)
|
||||
{
|
||||
clear_speculation ();
|
||||
return true;
|
||||
@ -2117,7 +2214,7 @@ ipa_polymorphic_call_context::restrict_to_inner_class (tree expected_type)
|
||||
}
|
||||
|
||||
if (!fld)
|
||||
goto give_up;
|
||||
goto no_useful_type_info;
|
||||
|
||||
type = TYPE_MAIN_VARIANT (TREE_TYPE (fld));
|
||||
cur_offset -= pos;
|
||||
@ -2149,8 +2246,20 @@ ipa_polymorphic_call_context::restrict_to_inner_class (tree expected_type)
|
||||
|| !tree_fits_shwi_p (TYPE_SIZE (subtype))
|
||||
|| tree_to_shwi (TYPE_SIZE (subtype)) <= 0
|
||||
|| !contains_polymorphic_type_p (subtype))
|
||||
goto give_up;
|
||||
cur_offset = cur_offset % tree_to_shwi (TYPE_SIZE (subtype));
|
||||
goto no_useful_type_info;
|
||||
|
||||
HOST_WIDE_INT new_offset = cur_offset % tree_to_shwi (TYPE_SIZE (subtype));
|
||||
|
||||
/* We may see buffer for placement new. In this case the expected type
|
||||
can be bigger than the subtype. */
|
||||
if (TYPE_SIZE (subtype)
|
||||
&& (cur_offset
|
||||
+ (expected_type ? tree_to_uhwi (TYPE_SIZE (expected_type))
|
||||
: 0)
|
||||
> tree_to_uhwi (TYPE_SIZE (type))))
|
||||
goto no_useful_type_info;
|
||||
|
||||
cur_offset = new_offset;
|
||||
type = subtype;
|
||||
if (!speculative)
|
||||
{
|
||||
@ -2167,31 +2276,48 @@ ipa_polymorphic_call_context::restrict_to_inner_class (tree expected_type)
|
||||
}
|
||||
/* Give up on anything else. */
|
||||
else
|
||||
goto give_up;
|
||||
{
|
||||
no_useful_type_info:
|
||||
/* We found no way to embedd EXPECTED_TYPE in TYPE.
|
||||
We still permit two special cases - placement new and
|
||||
the case of variadic types containing themselves. */
|
||||
if (!speculative
|
||||
&& (size_unknown || !type
|
||||
|| possible_placement_new (type, expected_type, cur_offset)))
|
||||
{
|
||||
/* In these weird cases we want to accept the context.
|
||||
In non-speculative run we have no useful outer_type info
|
||||
(TODO: we may eventually want to record upper bound on the
|
||||
type size that can be used to prune the walk),
|
||||
but we still want to consider speculation that may
|
||||
give useful info. */
|
||||
if (!speculative)
|
||||
{
|
||||
clear_outer_type (expected_type);
|
||||
if (speculative_outer_type)
|
||||
{
|
||||
speculative = true;
|
||||
type = speculative_outer_type;
|
||||
cur_offset = speculative_offset;
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
else
|
||||
clear_speculation ();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
clear_speculation ();
|
||||
if (speculative)
|
||||
return true;
|
||||
clear_outer_type (expected_type);
|
||||
invalid = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If we failed to find subtype we look for, give up and fall back to the
|
||||
most generic query. */
|
||||
give_up:
|
||||
clear_speculation ();
|
||||
if (valid)
|
||||
return true;
|
||||
outer_type = expected_type;
|
||||
offset = 0;
|
||||
maybe_derived_type = true;
|
||||
maybe_in_construction = true;
|
||||
/* POD can be changed to an instance of a polymorphic type by
|
||||
placement new. Here we play safe and assume that any
|
||||
non-polymorphic type is POD. */
|
||||
if ((TREE_CODE (type) != RECORD_TYPE
|
||||
|| !TYPE_BINFO (type)
|
||||
|| !polymorphic_type_binfo_p (TYPE_BINFO (type)))
|
||||
&& (!TYPE_SIZE (type)
|
||||
|| TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST
|
||||
|| (cur_offset + tree_to_uhwi (TYPE_SIZE (expected_type)) <=
|
||||
tree_to_uhwi (TYPE_SIZE (type)))))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Return true if OUTER_TYPE contains OTR_TYPE at OFFSET. */
|
||||
@ -2203,6 +2329,7 @@ contains_type_p (tree outer_type, HOST_WIDE_INT offset,
|
||||
ipa_polymorphic_call_context context;
|
||||
context.offset = offset;
|
||||
context.outer_type = TYPE_MAIN_VARIANT (outer_type);
|
||||
context.maybe_derived_type = false;
|
||||
return context.restrict_to_inner_class (otr_type);
|
||||
}
|
||||
|
||||
@ -2399,6 +2526,50 @@ decl_maybe_in_construction_p (tree base, tree outer_type,
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Dump human readable context to F. */
|
||||
|
||||
void
|
||||
ipa_polymorphic_call_context::dump (FILE *f) const
|
||||
{
|
||||
fprintf (f, " ");
|
||||
if (invalid)
|
||||
fprintf (f, "Call is known to be undefined\n");
|
||||
else
|
||||
{
|
||||
if (!outer_type && !offset && !speculative_outer_type)
|
||||
fprintf (f, "Empty context\n");
|
||||
if (outer_type || offset)
|
||||
{
|
||||
fprintf (f, "Outer type:");
|
||||
print_generic_expr (f, outer_type, TDF_SLIM);
|
||||
if (maybe_derived_type)
|
||||
fprintf (f, " (or a derived type)");
|
||||
if (maybe_in_construction)
|
||||
fprintf (f, " (maybe in construction)");
|
||||
fprintf (f, " offset "HOST_WIDE_INT_PRINT_DEC,
|
||||
offset);
|
||||
}
|
||||
if (speculative_outer_type)
|
||||
{
|
||||
fprintf (f, " speculative outer type:");
|
||||
print_generic_expr (f, speculative_outer_type, TDF_SLIM);
|
||||
if (speculative_maybe_derived_type)
|
||||
fprintf (f, " (or a derived type)");
|
||||
fprintf (f, " at offset "HOST_WIDE_INT_PRINT_DEC,
|
||||
speculative_offset);
|
||||
}
|
||||
}
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
|
||||
/* Print context to stderr. */
|
||||
|
||||
void
|
||||
ipa_polymorphic_call_context::debug () const
|
||||
{
|
||||
dump (stderr);
|
||||
}
|
||||
|
||||
/* Proudce polymorphic call context for call method of instance
|
||||
that is located within BASE (that is assumed to be a decl) at offset OFF. */
|
||||
|
||||
@ -2412,8 +2583,9 @@ ipa_polymorphic_call_context::set_by_decl (tree base, HOST_WIDE_INT off)
|
||||
clear_speculation ();
|
||||
/* Make very conservative assumption that all objects
|
||||
may be in construction.
|
||||
TODO: ipa-prop already contains code to tell better.
|
||||
merge it later. */
|
||||
|
||||
It is up to caller to revisit this via
|
||||
get_dynamic_type or decl_maybe_in_construction_p. */
|
||||
maybe_in_construction = true;
|
||||
maybe_derived_type = false;
|
||||
}
|
||||
@ -2433,9 +2605,7 @@ ipa_polymorphic_call_context::set_by_invariant (tree cst,
|
||||
|
||||
invalid = false;
|
||||
off = 0;
|
||||
outer_type = NULL;
|
||||
maybe_in_construction = true;
|
||||
maybe_derived_type = true;
|
||||
clear_outer_type (otr_type);
|
||||
|
||||
if (TREE_CODE (cst) != ADDR_EXPR)
|
||||
return false;
|
||||
@ -2448,10 +2618,7 @@ ipa_polymorphic_call_context::set_by_invariant (tree cst,
|
||||
/* Only type inconsistent programs can have otr_type that is
|
||||
not part of outer type. */
|
||||
if (otr_type && !contains_type_p (TREE_TYPE (base), off, otr_type))
|
||||
{
|
||||
invalid = true;
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
|
||||
set_by_decl (base, off);
|
||||
return true;
|
||||
@ -2512,10 +2679,7 @@ ipa_polymorphic_call_context::ipa_polymorphic_call_context (tree fndecl,
|
||||
|
||||
/* Set up basic info in case we find nothing interesting in the analysis. */
|
||||
clear_speculation ();
|
||||
outer_type = TYPE_MAIN_VARIANT (otr_type);
|
||||
offset = 0;
|
||||
maybe_derived_type = true;
|
||||
maybe_in_construction = true;
|
||||
clear_outer_type (otr_type);
|
||||
invalid = false;
|
||||
|
||||
/* Walk SSA for outer object. */
|
||||
@ -3489,18 +3653,21 @@ possible_polymorphic_call_targets (tree otr_type,
|
||||
gcc_assert (!context.outer_type
|
||||
|| TYPE_MAIN_VARIANT (context.outer_type) == context.outer_type);
|
||||
|
||||
/* Lookup the outer class type we want to walk. */
|
||||
/* Lookup the outer class type we want to walk.
|
||||
If we fail to do so, the context is invalid. */
|
||||
if ((context.outer_type || context.speculative_outer_type)
|
||||
&& !context.restrict_to_inner_class (otr_type))
|
||||
{
|
||||
fprintf (stderr, "Invalid\n");
|
||||
if (completep)
|
||||
*completep = false;
|
||||
*completep = true;
|
||||
if (cache_token)
|
||||
*cache_token = NULL;
|
||||
if (speculative_targetsp)
|
||||
*speculative_targetsp = 0;
|
||||
return nodes;
|
||||
}
|
||||
gcc_assert (!context.invalid);
|
||||
|
||||
/* Check that restrict_to_inner_class kept the main variant. */
|
||||
gcc_assert (!context.outer_type
|
||||
@ -3652,10 +3819,7 @@ possible_polymorphic_call_targets (tree otr_type,
|
||||
if (type_possibly_instantiated_p (outer_type->type))
|
||||
maybe_record_node (nodes, target, &inserted, can_refer, &complete);
|
||||
else
|
||||
{
|
||||
skipped = true;
|
||||
gcc_assert (in_lto_p || context.maybe_derived_type);
|
||||
}
|
||||
skipped = true;
|
||||
|
||||
if (binfo)
|
||||
matched_vtables.add (BINFO_VTABLE (binfo));
|
||||
@ -3789,20 +3953,8 @@ dump_possible_polymorphic_call_targets (FILE *f,
|
||||
fprintf (f, " Targets of polymorphic call of type %i:", type->id);
|
||||
print_generic_expr (f, type->type, TDF_SLIM);
|
||||
fprintf (f, " token %i\n", (int)otr_token);
|
||||
if (ctx.outer_type || ctx.offset)
|
||||
{
|
||||
fprintf (f, " Contained in type:");
|
||||
print_generic_expr (f, ctx.outer_type, TDF_SLIM);
|
||||
fprintf (f, " at offset "HOST_WIDE_INT_PRINT_DEC"\n",
|
||||
ctx.offset);
|
||||
}
|
||||
if (ctx.speculative_outer_type)
|
||||
{
|
||||
fprintf (f, " Speculatively contained in type:");
|
||||
print_generic_expr (f, ctx.speculative_outer_type, TDF_SLIM);
|
||||
fprintf (f, " at offset "HOST_WIDE_INT_PRINT_DEC"\n",
|
||||
ctx.speculative_offset);
|
||||
}
|
||||
|
||||
ctx.dump (f);
|
||||
|
||||
fprintf (f, " %s%s%s%s\n ",
|
||||
final ? "This is a complete list." :
|
||||
|
@ -2357,7 +2357,8 @@ ipa_analyze_call_uses (struct func_body_info *fbi, gimple call)
|
||||
|
||||
if (context.get_dynamic_type (instance,
|
||||
OBJ_TYPE_REF_OBJECT (target),
|
||||
otr_type, call))
|
||||
otr_type, call)
|
||||
&& context.offset == cs->indirect_info->offset)
|
||||
{
|
||||
gcc_assert (TREE_CODE (otr_type) == RECORD_TYPE);
|
||||
cs->indirect_info->polymorphic = true;
|
||||
|
@ -83,9 +83,14 @@ public:
|
||||
containing EXPECTED_TYPE as base class. */
|
||||
bool restrict_to_inner_class (tree expected_type);
|
||||
|
||||
/* Dump human readable context to F. */
|
||||
void dump (FILE *f) const;
|
||||
void DEBUG_FUNCTION debug () const;
|
||||
|
||||
private:
|
||||
void set_by_decl (tree, HOST_WIDE_INT);
|
||||
bool set_by_invariant (tree, tree, HOST_WIDE_INT);
|
||||
void clear_outer_type (tree otr_type = NULL);
|
||||
};
|
||||
|
||||
/* Build polymorphic call context for indirect call E. */
|
||||
@ -110,13 +115,8 @@ ipa_polymorphic_call_context::ipa_polymorphic_call_context (cgraph_edge *e)
|
||||
inline
|
||||
ipa_polymorphic_call_context::ipa_polymorphic_call_context ()
|
||||
{
|
||||
offset = 0;
|
||||
speculative_offset = 0;
|
||||
outer_type = NULL;
|
||||
speculative_outer_type = NULL;
|
||||
maybe_in_construction = true;
|
||||
maybe_derived_type = true;
|
||||
speculative_maybe_derived_type = false;
|
||||
clear_speculation ();
|
||||
clear_outer_type ();
|
||||
invalid = false;
|
||||
}
|
||||
|
||||
@ -130,6 +130,19 @@ ipa_polymorphic_call_context::clear_speculation ()
|
||||
speculative_maybe_derived_type = false;
|
||||
}
|
||||
|
||||
/* Produce context specifying all derrived types of OTR_TYPE.
|
||||
If OTR_TYPE is NULL or type of the OBJ_TYPE_REF, the context is set
|
||||
to dummy "I know nothing" setting. */
|
||||
|
||||
inline void
|
||||
ipa_polymorphic_call_context::clear_outer_type (tree otr_type)
|
||||
{
|
||||
outer_type = otr_type ? TYPE_MAIN_VARIANT (otr_type) : NULL;
|
||||
offset = 0;
|
||||
maybe_derived_type = true;
|
||||
maybe_in_construction = true;
|
||||
}
|
||||
|
||||
/* In ipa-utils.c */
|
||||
void ipa_print_order (FILE*, const char *, struct cgraph_node**, int);
|
||||
int ipa_reduced_postorder (struct cgraph_node **, bool, bool,
|
||||
|
Loading…
Reference in New Issue
Block a user