138fd1498Szrj /* Analysis of polymorphic call context.
238fd1498Szrj Copyright (C) 2013-2018 Free Software Foundation, Inc.
338fd1498Szrj Contributed by Jan Hubicka
438fd1498Szrj
538fd1498Szrj This file is part of GCC.
638fd1498Szrj
738fd1498Szrj GCC is free software; you can redistribute it and/or modify it under
838fd1498Szrj the terms of the GNU General Public License as published by the Free
938fd1498Szrj Software Foundation; either version 3, or (at your option) any later
1038fd1498Szrj version.
1138fd1498Szrj
1238fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT ANY
1338fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or
1438fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1538fd1498Szrj for more details.
1638fd1498Szrj
1738fd1498Szrj You should have received a copy of the GNU General Public License
1838fd1498Szrj along with GCC; see the file COPYING3. If not see
1938fd1498Szrj <http://www.gnu.org/licenses/>. */
2038fd1498Szrj
2138fd1498Szrj #include "config.h"
2238fd1498Szrj #include "system.h"
2338fd1498Szrj #include "coretypes.h"
2438fd1498Szrj #include "backend.h"
2538fd1498Szrj #include "rtl.h"
2638fd1498Szrj #include "tree.h"
2738fd1498Szrj #include "gimple.h"
2838fd1498Szrj #include "tree-pass.h"
2938fd1498Szrj #include "tree-ssa-operands.h"
3038fd1498Szrj #include "streamer-hooks.h"
3138fd1498Szrj #include "cgraph.h"
3238fd1498Szrj #include "data-streamer.h"
3338fd1498Szrj #include "diagnostic.h"
3438fd1498Szrj #include "alias.h"
3538fd1498Szrj #include "fold-const.h"
3638fd1498Szrj #include "calls.h"
3738fd1498Szrj #include "ipa-utils.h"
3838fd1498Szrj #include "tree-dfa.h"
3938fd1498Szrj #include "gimple-pretty-print.h"
4038fd1498Szrj #include "tree-into-ssa.h"
4138fd1498Szrj #include "params.h"
4238fd1498Szrj
4338fd1498Szrj /* Return true when TYPE contains an polymorphic type and thus is interesting
4438fd1498Szrj for devirtualization machinery. */
4538fd1498Szrj
4638fd1498Szrj static bool contains_type_p (tree, HOST_WIDE_INT, tree,
4738fd1498Szrj bool consider_placement_new = true,
4838fd1498Szrj bool consider_bases = true);
4938fd1498Szrj
5038fd1498Szrj bool
contains_polymorphic_type_p(const_tree type)5138fd1498Szrj contains_polymorphic_type_p (const_tree type)
5238fd1498Szrj {
5338fd1498Szrj type = TYPE_MAIN_VARIANT (type);
5438fd1498Szrj
5538fd1498Szrj if (RECORD_OR_UNION_TYPE_P (type))
5638fd1498Szrj {
5738fd1498Szrj if (TYPE_BINFO (type)
5838fd1498Szrj && polymorphic_type_binfo_p (TYPE_BINFO (type)))
5938fd1498Szrj return true;
6038fd1498Szrj for (tree fld = TYPE_FIELDS (type); fld; fld = DECL_CHAIN (fld))
6138fd1498Szrj if (TREE_CODE (fld) == FIELD_DECL
6238fd1498Szrj && !DECL_ARTIFICIAL (fld)
6338fd1498Szrj && contains_polymorphic_type_p (TREE_TYPE (fld)))
6438fd1498Szrj return true;
6538fd1498Szrj return false;
6638fd1498Szrj }
6738fd1498Szrj if (TREE_CODE (type) == ARRAY_TYPE)
6838fd1498Szrj return contains_polymorphic_type_p (TREE_TYPE (type));
6938fd1498Szrj return false;
7038fd1498Szrj }
7138fd1498Szrj
7238fd1498Szrj /* Return true if it seems valid to use placement new to build EXPECTED_TYPE
7338fd1498Szrj at possition CUR_OFFSET within TYPE.
7438fd1498Szrj
7538fd1498Szrj POD can be changed to an instance of a polymorphic type by
7638fd1498Szrj placement new. Here we play safe and assume that any
7738fd1498Szrj non-polymorphic type is POD. */
7838fd1498Szrj bool
possible_placement_new(tree type,tree expected_type,HOST_WIDE_INT cur_offset)7938fd1498Szrj possible_placement_new (tree type, tree expected_type,
8038fd1498Szrj HOST_WIDE_INT cur_offset)
8138fd1498Szrj {
8238fd1498Szrj if (cur_offset < 0)
8338fd1498Szrj return true;
8438fd1498Szrj return ((TREE_CODE (type) != RECORD_TYPE
8538fd1498Szrj || !TYPE_BINFO (type)
8638fd1498Szrj || cur_offset >= POINTER_SIZE
8738fd1498Szrj || !polymorphic_type_binfo_p (TYPE_BINFO (type)))
8838fd1498Szrj && (!TYPE_SIZE (type)
8938fd1498Szrj || !tree_fits_shwi_p (TYPE_SIZE (type))
9038fd1498Szrj || (cur_offset
9138fd1498Szrj + (expected_type ? tree_to_uhwi (TYPE_SIZE (expected_type))
9238fd1498Szrj : POINTER_SIZE)
9338fd1498Szrj <= tree_to_uhwi (TYPE_SIZE (type)))));
9438fd1498Szrj }
9538fd1498Szrj
9638fd1498Szrj /* THIS->OUTER_TYPE is a type of memory object where object of OTR_TYPE
9738fd1498Szrj is contained at THIS->OFFSET. Walk the memory representation of
9838fd1498Szrj THIS->OUTER_TYPE and find the outermost class type that match
9938fd1498Szrj OTR_TYPE or contain OTR_TYPE as a base. Update THIS
10038fd1498Szrj to represent it.
10138fd1498Szrj
10238fd1498Szrj If OTR_TYPE is NULL, just find outermost polymorphic type with
10338fd1498Szrj virtual table present at possition OFFSET.
10438fd1498Szrj
10538fd1498Szrj For example when THIS represents type
10638fd1498Szrj class A
10738fd1498Szrj {
10838fd1498Szrj int a;
10938fd1498Szrj class B b;
11038fd1498Szrj }
11138fd1498Szrj and we look for type at offset sizeof(int), we end up with B and offset 0.
11238fd1498Szrj If the same is produced by multiple inheritance, we end up with A and offset
11338fd1498Szrj sizeof(int).
11438fd1498Szrj
11538fd1498Szrj If we can not find corresponding class, give up by setting
11638fd1498Szrj THIS->OUTER_TYPE to OTR_TYPE and THIS->OFFSET to NULL.
11738fd1498Szrj Return true when lookup was sucesful.
11838fd1498Szrj
11938fd1498Szrj When CONSIDER_PLACEMENT_NEW is false, reject contexts that may be made
12038fd1498Szrj valid only via allocation of new polymorphic type inside by means
12138fd1498Szrj of placement new.
12238fd1498Szrj
12338fd1498Szrj When CONSIDER_BASES is false, only look for actual fields, not base types
12438fd1498Szrj of TYPE. */
12538fd1498Szrj
12638fd1498Szrj bool
restrict_to_inner_class(tree otr_type,bool consider_placement_new,bool consider_bases)12738fd1498Szrj ipa_polymorphic_call_context::restrict_to_inner_class (tree otr_type,
12838fd1498Szrj bool consider_placement_new,
12938fd1498Szrj bool consider_bases)
13038fd1498Szrj {
13138fd1498Szrj tree type = outer_type;
13238fd1498Szrj HOST_WIDE_INT cur_offset = offset;
13338fd1498Szrj bool speculative = false;
13438fd1498Szrj bool size_unknown = false;
13538fd1498Szrj unsigned HOST_WIDE_INT otr_type_size = POINTER_SIZE;
13638fd1498Szrj
13738fd1498Szrj /* Update OUTER_TYPE to match EXPECTED_TYPE if it is not set. */
13838fd1498Szrj if (!outer_type)
13938fd1498Szrj {
14038fd1498Szrj clear_outer_type (otr_type);
14138fd1498Szrj type = otr_type;
14238fd1498Szrj cur_offset = 0;
14338fd1498Szrj }
14438fd1498Szrj /* See if OFFSET points inside OUTER_TYPE. If it does not, we know
14538fd1498Szrj that the context is either invalid, or the instance type must be
14638fd1498Szrj derived from OUTER_TYPE.
14738fd1498Szrj
14838fd1498Szrj Because the instance type may contain field whose type is of OUTER_TYPE,
14938fd1498Szrj we can not derive any effective information about it.
15038fd1498Szrj
15138fd1498Szrj TODO: In the case we know all derrived types, we can definitely do better
15238fd1498Szrj here. */
15338fd1498Szrj else if (TYPE_SIZE (outer_type)
15438fd1498Szrj && tree_fits_shwi_p (TYPE_SIZE (outer_type))
15538fd1498Szrj && tree_to_shwi (TYPE_SIZE (outer_type)) >= 0
15638fd1498Szrj && tree_to_shwi (TYPE_SIZE (outer_type)) <= offset)
15738fd1498Szrj {
15838fd1498Szrj bool der = maybe_derived_type; /* clear_outer_type will reset it. */
15938fd1498Szrj bool dyn = dynamic;
16038fd1498Szrj clear_outer_type (otr_type);
16138fd1498Szrj type = otr_type;
16238fd1498Szrj cur_offset = 0;
16338fd1498Szrj
16438fd1498Szrj /* If derived type is not allowed, we know that the context is invalid.
16538fd1498Szrj For dynamic types, we really do not have information about
16638fd1498Szrj size of the memory location. It is possible that completely
16738fd1498Szrj different type is stored after outer_type. */
16838fd1498Szrj if (!der && !dyn)
16938fd1498Szrj {
17038fd1498Szrj clear_speculation ();
17138fd1498Szrj invalid = true;
17238fd1498Szrj return false;
17338fd1498Szrj }
17438fd1498Szrj }
17538fd1498Szrj
17638fd1498Szrj if (otr_type && TYPE_SIZE (otr_type)
17738fd1498Szrj && tree_fits_shwi_p (TYPE_SIZE (otr_type)))
17838fd1498Szrj otr_type_size = tree_to_uhwi (TYPE_SIZE (otr_type));
17938fd1498Szrj
18038fd1498Szrj if (!type || offset < 0)
18138fd1498Szrj goto no_useful_type_info;
18238fd1498Szrj
18338fd1498Szrj /* Find the sub-object the constant actually refers to and mark whether it is
18438fd1498Szrj an artificial one (as opposed to a user-defined one).
18538fd1498Szrj
18638fd1498Szrj This loop is performed twice; first time for outer_type and second time
18738fd1498Szrj for speculative_outer_type. The second run has SPECULATIVE set. */
18838fd1498Szrj while (true)
18938fd1498Szrj {
19038fd1498Szrj unsigned HOST_WIDE_INT pos, size;
19138fd1498Szrj tree fld;
19238fd1498Szrj
19338fd1498Szrj /* If we do not know size of TYPE, we need to be more conservative
19438fd1498Szrj about accepting cases where we can not find EXPECTED_TYPE.
19538fd1498Szrj Generally the types that do matter here are of constant size.
19638fd1498Szrj Size_unknown case should be very rare. */
19738fd1498Szrj if (TYPE_SIZE (type)
19838fd1498Szrj && tree_fits_shwi_p (TYPE_SIZE (type))
19938fd1498Szrj && tree_to_shwi (TYPE_SIZE (type)) >= 0)
20038fd1498Szrj size_unknown = false;
20138fd1498Szrj else
20238fd1498Szrj size_unknown = true;
20338fd1498Szrj
20438fd1498Szrj /* On a match, just return what we found. */
20538fd1498Szrj if ((otr_type
20638fd1498Szrj && types_odr_comparable (type, otr_type)
20738fd1498Szrj && types_same_for_odr (type, otr_type))
20838fd1498Szrj || (!otr_type
20938fd1498Szrj && TREE_CODE (type) == RECORD_TYPE
21038fd1498Szrj && TYPE_BINFO (type)
21138fd1498Szrj && polymorphic_type_binfo_p (TYPE_BINFO (type))))
21238fd1498Szrj {
21338fd1498Szrj if (speculative)
21438fd1498Szrj {
21538fd1498Szrj /* If we did not match the offset, just give up on speculation. */
21638fd1498Szrj if (cur_offset != 0
21738fd1498Szrj /* Also check if speculation did not end up being same as
21838fd1498Szrj non-speculation. */
21938fd1498Szrj || (types_must_be_same_for_odr (speculative_outer_type,
22038fd1498Szrj outer_type)
22138fd1498Szrj && (maybe_derived_type
22238fd1498Szrj == speculative_maybe_derived_type)))
22338fd1498Szrj clear_speculation ();
22438fd1498Szrj return true;
22538fd1498Szrj }
22638fd1498Szrj else
22738fd1498Szrj {
22838fd1498Szrj /* If type is known to be final, do not worry about derived
22938fd1498Szrj types. Testing it here may help us to avoid speculation. */
23038fd1498Szrj if (otr_type && TREE_CODE (outer_type) == RECORD_TYPE
23138fd1498Szrj && (!in_lto_p || odr_type_p (outer_type))
23238fd1498Szrj && type_with_linkage_p (outer_type)
23338fd1498Szrj && type_known_to_have_no_derivations_p (outer_type))
23438fd1498Szrj maybe_derived_type = false;
23538fd1498Szrj
23638fd1498Szrj /* Type can not contain itself on an non-zero offset. In that case
23738fd1498Szrj just give up. Still accept the case where size is now known.
23838fd1498Szrj Either the second copy may appear past the end of type or within
23938fd1498Szrj the non-POD buffer located inside the variably sized type
24038fd1498Szrj itself. */
24138fd1498Szrj if (cur_offset != 0)
24238fd1498Szrj goto no_useful_type_info;
24338fd1498Szrj /* If we determined type precisely or we have no clue on
24438fd1498Szrj speuclation, we are done. */
24538fd1498Szrj if (!maybe_derived_type || !speculative_outer_type
24638fd1498Szrj || !speculation_consistent_p (speculative_outer_type,
24738fd1498Szrj speculative_offset,
24838fd1498Szrj speculative_maybe_derived_type,
24938fd1498Szrj otr_type))
25038fd1498Szrj {
25138fd1498Szrj clear_speculation ();
25238fd1498Szrj return true;
25338fd1498Szrj }
25438fd1498Szrj /* Otherwise look into speculation now. */
25538fd1498Szrj else
25638fd1498Szrj {
25738fd1498Szrj speculative = true;
25838fd1498Szrj type = speculative_outer_type;
25938fd1498Szrj cur_offset = speculative_offset;
26038fd1498Szrj continue;
26138fd1498Szrj }
26238fd1498Szrj }
26338fd1498Szrj }
26438fd1498Szrj
26538fd1498Szrj /* Walk fields and find corresponding on at OFFSET. */
26638fd1498Szrj if (TREE_CODE (type) == RECORD_TYPE)
26738fd1498Szrj {
26838fd1498Szrj for (fld = TYPE_FIELDS (type); fld; fld = DECL_CHAIN (fld))
26938fd1498Szrj {
27038fd1498Szrj if (TREE_CODE (fld) != FIELD_DECL
27138fd1498Szrj || TREE_TYPE (fld) == error_mark_node)
27238fd1498Szrj continue;
27338fd1498Szrj
27438fd1498Szrj pos = int_bit_position (fld);
27538fd1498Szrj if (pos > (unsigned HOST_WIDE_INT)cur_offset)
27638fd1498Szrj continue;
27738fd1498Szrj
27838fd1498Szrj /* Do not consider vptr itself. Not even for placement new. */
27938fd1498Szrj if (!pos && DECL_ARTIFICIAL (fld)
28038fd1498Szrj && POINTER_TYPE_P (TREE_TYPE (fld))
28138fd1498Szrj && TYPE_BINFO (type)
28238fd1498Szrj && polymorphic_type_binfo_p (TYPE_BINFO (type)))
28338fd1498Szrj continue;
28438fd1498Szrj
28538fd1498Szrj if (!DECL_SIZE (fld) || !tree_fits_uhwi_p (DECL_SIZE (fld)))
28638fd1498Szrj goto no_useful_type_info;
28738fd1498Szrj size = tree_to_uhwi (DECL_SIZE (fld));
28838fd1498Szrj
28938fd1498Szrj /* We can always skip types smaller than pointer size:
29038fd1498Szrj those can not contain a virtual table pointer.
29138fd1498Szrj
29238fd1498Szrj Disqualifying fields that are too small to fit OTR_TYPE
29338fd1498Szrj saves work needed to walk them for no benefit.
29438fd1498Szrj Because of the way the bases are packed into a class, the
29538fd1498Szrj field's size may be smaller than type size, so it needs
29638fd1498Szrj to be done with a care. */
29738fd1498Szrj
29838fd1498Szrj if (pos <= (unsigned HOST_WIDE_INT)cur_offset
29938fd1498Szrj && (pos + size) >= (unsigned HOST_WIDE_INT)cur_offset
30038fd1498Szrj + POINTER_SIZE
30138fd1498Szrj && (!otr_type
30238fd1498Szrj || !TYPE_SIZE (TREE_TYPE (fld))
30338fd1498Szrj || !tree_fits_shwi_p (TYPE_SIZE (TREE_TYPE (fld)))
30438fd1498Szrj || (pos + tree_to_uhwi (TYPE_SIZE (TREE_TYPE (fld))))
30538fd1498Szrj >= cur_offset + otr_type_size))
30638fd1498Szrj break;
30738fd1498Szrj }
30838fd1498Szrj
30938fd1498Szrj if (!fld)
31038fd1498Szrj goto no_useful_type_info;
31138fd1498Szrj
31238fd1498Szrj type = TYPE_MAIN_VARIANT (TREE_TYPE (fld));
31338fd1498Szrj cur_offset -= pos;
31438fd1498Szrj /* DECL_ARTIFICIAL represents a basetype. */
31538fd1498Szrj if (!DECL_ARTIFICIAL (fld))
31638fd1498Szrj {
31738fd1498Szrj if (!speculative)
31838fd1498Szrj {
31938fd1498Szrj outer_type = type;
32038fd1498Szrj offset = cur_offset;
32138fd1498Szrj /* As soon as we se an field containing the type,
32238fd1498Szrj we know we are not looking for derivations. */
32338fd1498Szrj maybe_derived_type = false;
32438fd1498Szrj }
32538fd1498Szrj else
32638fd1498Szrj {
32738fd1498Szrj speculative_outer_type = type;
32838fd1498Szrj speculative_offset = cur_offset;
32938fd1498Szrj speculative_maybe_derived_type = false;
33038fd1498Szrj }
33138fd1498Szrj }
33238fd1498Szrj else if (!consider_bases)
33338fd1498Szrj goto no_useful_type_info;
33438fd1498Szrj }
33538fd1498Szrj else if (TREE_CODE (type) == ARRAY_TYPE)
33638fd1498Szrj {
33738fd1498Szrj tree subtype = TYPE_MAIN_VARIANT (TREE_TYPE (type));
33838fd1498Szrj
33938fd1498Szrj /* Give up if we don't know array field size.
34038fd1498Szrj Also give up on non-polymorphic types as they are used
34138fd1498Szrj as buffers for placement new. */
34238fd1498Szrj if (!TYPE_SIZE (subtype)
34338fd1498Szrj || !tree_fits_shwi_p (TYPE_SIZE (subtype))
34438fd1498Szrj || tree_to_shwi (TYPE_SIZE (subtype)) <= 0
34538fd1498Szrj || !contains_polymorphic_type_p (subtype))
34638fd1498Szrj goto no_useful_type_info;
34738fd1498Szrj
34838fd1498Szrj HOST_WIDE_INT new_offset = cur_offset % tree_to_shwi (TYPE_SIZE (subtype));
34938fd1498Szrj
35038fd1498Szrj /* We may see buffer for placement new. In this case the expected type
35138fd1498Szrj can be bigger than the subtype. */
35238fd1498Szrj if (TYPE_SIZE (subtype)
35338fd1498Szrj && (cur_offset + otr_type_size
35438fd1498Szrj > tree_to_uhwi (TYPE_SIZE (subtype))))
35538fd1498Szrj goto no_useful_type_info;
35638fd1498Szrj
35738fd1498Szrj cur_offset = new_offset;
35838fd1498Szrj type = TYPE_MAIN_VARIANT (subtype);
35938fd1498Szrj if (!speculative)
36038fd1498Szrj {
36138fd1498Szrj outer_type = type;
36238fd1498Szrj offset = cur_offset;
36338fd1498Szrj maybe_derived_type = false;
36438fd1498Szrj }
36538fd1498Szrj else
36638fd1498Szrj {
36738fd1498Szrj speculative_outer_type = type;
36838fd1498Szrj speculative_offset = cur_offset;
36938fd1498Szrj speculative_maybe_derived_type = false;
37038fd1498Szrj }
37138fd1498Szrj }
37238fd1498Szrj /* Give up on anything else. */
37338fd1498Szrj else
37438fd1498Szrj {
37538fd1498Szrj no_useful_type_info:
37638fd1498Szrj if (maybe_derived_type && !speculative
37738fd1498Szrj && TREE_CODE (outer_type) == RECORD_TYPE
37838fd1498Szrj && TREE_CODE (otr_type) == RECORD_TYPE
37938fd1498Szrj && TYPE_BINFO (otr_type)
38038fd1498Szrj && !offset
38138fd1498Szrj && get_binfo_at_offset (TYPE_BINFO (otr_type), 0, outer_type))
38238fd1498Szrj {
38338fd1498Szrj clear_outer_type (otr_type);
38438fd1498Szrj if (!speculative_outer_type
38538fd1498Szrj || !speculation_consistent_p (speculative_outer_type,
38638fd1498Szrj speculative_offset,
38738fd1498Szrj speculative_maybe_derived_type,
38838fd1498Szrj otr_type))
38938fd1498Szrj clear_speculation ();
39038fd1498Szrj if (speculative_outer_type)
39138fd1498Szrj {
39238fd1498Szrj speculative = true;
39338fd1498Szrj type = speculative_outer_type;
39438fd1498Szrj cur_offset = speculative_offset;
39538fd1498Szrj }
39638fd1498Szrj else
39738fd1498Szrj return true;
39838fd1498Szrj }
39938fd1498Szrj /* We found no way to embedd EXPECTED_TYPE in TYPE.
40038fd1498Szrj We still permit two special cases - placement new and
40138fd1498Szrj the case of variadic types containing themselves. */
40238fd1498Szrj if (!speculative
40338fd1498Szrj && consider_placement_new
40438fd1498Szrj && (size_unknown || !type || maybe_derived_type
40538fd1498Szrj || possible_placement_new (type, otr_type, cur_offset)))
40638fd1498Szrj {
40738fd1498Szrj /* In these weird cases we want to accept the context.
40838fd1498Szrj In non-speculative run we have no useful outer_type info
40938fd1498Szrj (TODO: we may eventually want to record upper bound on the
41038fd1498Szrj type size that can be used to prune the walk),
41138fd1498Szrj but we still want to consider speculation that may
41238fd1498Szrj give useful info. */
41338fd1498Szrj if (!speculative)
41438fd1498Szrj {
41538fd1498Szrj clear_outer_type (otr_type);
41638fd1498Szrj if (!speculative_outer_type
41738fd1498Szrj || !speculation_consistent_p (speculative_outer_type,
41838fd1498Szrj speculative_offset,
41938fd1498Szrj speculative_maybe_derived_type,
42038fd1498Szrj otr_type))
42138fd1498Szrj clear_speculation ();
42238fd1498Szrj if (speculative_outer_type)
42338fd1498Szrj {
42438fd1498Szrj speculative = true;
42538fd1498Szrj type = speculative_outer_type;
42638fd1498Szrj cur_offset = speculative_offset;
42738fd1498Szrj }
42838fd1498Szrj else
42938fd1498Szrj return true;
43038fd1498Szrj }
43138fd1498Szrj else
43238fd1498Szrj {
43338fd1498Szrj clear_speculation ();
43438fd1498Szrj return true;
43538fd1498Szrj }
43638fd1498Szrj }
43738fd1498Szrj else
43838fd1498Szrj {
43938fd1498Szrj clear_speculation ();
44038fd1498Szrj if (speculative)
44138fd1498Szrj return true;
44238fd1498Szrj clear_outer_type (otr_type);
44338fd1498Szrj invalid = true;
44438fd1498Szrj return false;
44538fd1498Szrj }
44638fd1498Szrj }
44738fd1498Szrj }
44838fd1498Szrj }
44938fd1498Szrj
45038fd1498Szrj /* Return true if OUTER_TYPE contains OTR_TYPE at OFFSET.
45138fd1498Szrj CONSIDER_PLACEMENT_NEW makes function to accept cases where OTR_TYPE can
45238fd1498Szrj be built within OUTER_TYPE by means of placement new. CONSIDER_BASES makes
45338fd1498Szrj function to accept cases where OTR_TYPE appears as base of OUTER_TYPE or as
45438fd1498Szrj base of one of fields of OUTER_TYPE. */
45538fd1498Szrj
45638fd1498Szrj static bool
contains_type_p(tree outer_type,HOST_WIDE_INT offset,tree otr_type,bool consider_placement_new,bool consider_bases)45738fd1498Szrj contains_type_p (tree outer_type, HOST_WIDE_INT offset,
45838fd1498Szrj tree otr_type,
45938fd1498Szrj bool consider_placement_new,
46038fd1498Szrj bool consider_bases)
46138fd1498Szrj {
46238fd1498Szrj ipa_polymorphic_call_context context;
46338fd1498Szrj
46438fd1498Szrj /* Check that type is within range. */
46538fd1498Szrj if (offset < 0)
46638fd1498Szrj return false;
46738fd1498Szrj
46838fd1498Szrj /* PR ipa/71207
46938fd1498Szrj As OUTER_TYPE can be a type which has a diamond virtual inheritance,
47038fd1498Szrj it's not necessary that INNER_TYPE will fit within OUTER_TYPE with
47138fd1498Szrj a given offset. It can happen that INNER_TYPE also contains a base object,
47238fd1498Szrj however it would point to the same instance in the OUTER_TYPE. */
47338fd1498Szrj
47438fd1498Szrj context.offset = offset;
47538fd1498Szrj context.outer_type = TYPE_MAIN_VARIANT (outer_type);
47638fd1498Szrj context.maybe_derived_type = false;
47738fd1498Szrj context.dynamic = false;
47838fd1498Szrj return context.restrict_to_inner_class (otr_type, consider_placement_new,
47938fd1498Szrj consider_bases);
48038fd1498Szrj }
48138fd1498Szrj
48238fd1498Szrj
48338fd1498Szrj /* Return a FUNCTION_DECL if FN represent a constructor or destructor.
48438fd1498Szrj If CHECK_CLONES is true, also check for clones of ctor/dtors. */
48538fd1498Szrj
48638fd1498Szrj tree
polymorphic_ctor_dtor_p(tree fn,bool check_clones)48738fd1498Szrj polymorphic_ctor_dtor_p (tree fn, bool check_clones)
48838fd1498Szrj {
48938fd1498Szrj if (TREE_CODE (TREE_TYPE (fn)) != METHOD_TYPE
49038fd1498Szrj || (!DECL_CXX_CONSTRUCTOR_P (fn) && !DECL_CXX_DESTRUCTOR_P (fn)))
49138fd1498Szrj {
49238fd1498Szrj if (!check_clones)
49338fd1498Szrj return NULL_TREE;
49438fd1498Szrj
49538fd1498Szrj /* Watch for clones where we constant propagated the first
49638fd1498Szrj argument (pointer to the instance). */
49738fd1498Szrj fn = DECL_ABSTRACT_ORIGIN (fn);
49838fd1498Szrj if (!fn
49938fd1498Szrj || TREE_CODE (TREE_TYPE (fn)) != METHOD_TYPE
50038fd1498Szrj || (!DECL_CXX_CONSTRUCTOR_P (fn) && !DECL_CXX_DESTRUCTOR_P (fn)))
50138fd1498Szrj return NULL_TREE;
50238fd1498Szrj }
50338fd1498Szrj
50438fd1498Szrj if (flags_from_decl_or_type (fn) & (ECF_PURE | ECF_CONST))
50538fd1498Szrj return NULL_TREE;
50638fd1498Szrj
50738fd1498Szrj return fn;
50838fd1498Szrj }
50938fd1498Szrj
51038fd1498Szrj /* Return a FUNCTION_DECL if BLOCK represents a constructor or destructor.
51138fd1498Szrj If CHECK_CLONES is true, also check for clones of ctor/dtors. */
51238fd1498Szrj
51338fd1498Szrj tree
inlined_polymorphic_ctor_dtor_block_p(tree block,bool check_clones)51438fd1498Szrj inlined_polymorphic_ctor_dtor_block_p (tree block, bool check_clones)
51538fd1498Szrj {
51638fd1498Szrj tree fn = block_ultimate_origin (block);
51738fd1498Szrj if (fn == NULL || TREE_CODE (fn) != FUNCTION_DECL)
51838fd1498Szrj return NULL_TREE;
51938fd1498Szrj
52038fd1498Szrj return polymorphic_ctor_dtor_p (fn, check_clones);
52138fd1498Szrj }
52238fd1498Szrj
52338fd1498Szrj
52438fd1498Szrj /* We know that the instance is stored in variable or parameter
52538fd1498Szrj (not dynamically allocated) and we want to disprove the fact
52638fd1498Szrj that it may be in construction at invocation of CALL.
52738fd1498Szrj
52838fd1498Szrj BASE represents memory location where instance is stored.
52938fd1498Szrj If BASE is NULL, it is assumed to be global memory.
53038fd1498Szrj OUTER_TYPE is known type of the instance or NULL if not
53138fd1498Szrj known.
53238fd1498Szrj
53338fd1498Szrj For the variable to be in construction we actually need to
53438fd1498Szrj be in constructor of corresponding global variable or
53538fd1498Szrj the inline stack of CALL must contain the constructor.
53638fd1498Szrj Check this condition. This check works safely only before
53738fd1498Szrj IPA passes, because inline stacks may become out of date
53838fd1498Szrj later. */
53938fd1498Szrj
54038fd1498Szrj bool
decl_maybe_in_construction_p(tree base,tree outer_type,gimple * call,tree function)54138fd1498Szrj decl_maybe_in_construction_p (tree base, tree outer_type,
54238fd1498Szrj gimple *call, tree function)
54338fd1498Szrj {
54438fd1498Szrj if (outer_type)
54538fd1498Szrj outer_type = TYPE_MAIN_VARIANT (outer_type);
54638fd1498Szrj gcc_assert (!base || DECL_P (base));
54738fd1498Szrj
54838fd1498Szrj /* After inlining the code unification optimizations may invalidate
54938fd1498Szrj inline stacks. Also we need to give up on global variables after
55038fd1498Szrj IPA, because addresses of these may have been propagated to their
55138fd1498Szrj constructors. */
55238fd1498Szrj if (DECL_STRUCT_FUNCTION (function)->after_inlining)
55338fd1498Szrj return true;
55438fd1498Szrj
55538fd1498Szrj /* Pure functions can not do any changes on the dynamic type;
55638fd1498Szrj that require writting to memory. */
55738fd1498Szrj if ((!base || !auto_var_in_fn_p (base, function))
55838fd1498Szrj && flags_from_decl_or_type (function) & (ECF_PURE | ECF_CONST))
55938fd1498Szrj return false;
56038fd1498Szrj
56138fd1498Szrj bool check_clones = !base || is_global_var (base);
56238fd1498Szrj for (tree block = gimple_block (call); block && TREE_CODE (block) == BLOCK;
56338fd1498Szrj block = BLOCK_SUPERCONTEXT (block))
56438fd1498Szrj if (tree fn = inlined_polymorphic_ctor_dtor_block_p (block, check_clones))
56538fd1498Szrj {
56638fd1498Szrj tree type = TYPE_METHOD_BASETYPE (TREE_TYPE (fn));
56738fd1498Szrj
56838fd1498Szrj if (!outer_type || !types_odr_comparable (type, outer_type))
56938fd1498Szrj {
57038fd1498Szrj if (TREE_CODE (type) == RECORD_TYPE
57138fd1498Szrj && TYPE_BINFO (type)
57238fd1498Szrj && polymorphic_type_binfo_p (TYPE_BINFO (type)))
57338fd1498Szrj return true;
57438fd1498Szrj }
57538fd1498Szrj else if (types_same_for_odr (type, outer_type))
57638fd1498Szrj return true;
57738fd1498Szrj }
57838fd1498Szrj
57938fd1498Szrj if (!base || (VAR_P (base) && is_global_var (base)))
58038fd1498Szrj {
58138fd1498Szrj if (TREE_CODE (TREE_TYPE (function)) != METHOD_TYPE
58238fd1498Szrj || (!DECL_CXX_CONSTRUCTOR_P (function)
58338fd1498Szrj && !DECL_CXX_DESTRUCTOR_P (function)))
58438fd1498Szrj {
58538fd1498Szrj if (!DECL_ABSTRACT_ORIGIN (function))
58638fd1498Szrj return false;
58738fd1498Szrj /* Watch for clones where we constant propagated the first
58838fd1498Szrj argument (pointer to the instance). */
58938fd1498Szrj function = DECL_ABSTRACT_ORIGIN (function);
59038fd1498Szrj if (!function
59138fd1498Szrj || TREE_CODE (TREE_TYPE (function)) != METHOD_TYPE
59238fd1498Szrj || (!DECL_CXX_CONSTRUCTOR_P (function)
59338fd1498Szrj && !DECL_CXX_DESTRUCTOR_P (function)))
59438fd1498Szrj return false;
59538fd1498Szrj }
59638fd1498Szrj tree type = TYPE_METHOD_BASETYPE (TREE_TYPE (function));
59738fd1498Szrj if (!outer_type || !types_odr_comparable (type, outer_type))
59838fd1498Szrj {
59938fd1498Szrj if (TREE_CODE (type) == RECORD_TYPE
60038fd1498Szrj && TYPE_BINFO (type)
60138fd1498Szrj && polymorphic_type_binfo_p (TYPE_BINFO (type)))
60238fd1498Szrj return true;
60338fd1498Szrj }
60438fd1498Szrj else if (types_same_for_odr (type, outer_type))
60538fd1498Szrj return true;
60638fd1498Szrj }
60738fd1498Szrj return false;
60838fd1498Szrj }
60938fd1498Szrj
61038fd1498Szrj /* Dump human readable context to F. If NEWLINE is true, it will be terminated
61138fd1498Szrj by a newline. */
61238fd1498Szrj
61338fd1498Szrj void
dump(FILE * f,bool newline)61438fd1498Szrj ipa_polymorphic_call_context::dump (FILE *f, bool newline) const
61538fd1498Szrj {
61638fd1498Szrj fprintf (f, " ");
61738fd1498Szrj if (invalid)
61838fd1498Szrj fprintf (f, "Call is known to be undefined");
61938fd1498Szrj else
62038fd1498Szrj {
62138fd1498Szrj if (useless_p ())
62238fd1498Szrj fprintf (f, "nothing known");
62338fd1498Szrj if (outer_type || offset)
62438fd1498Szrj {
62538fd1498Szrj fprintf (f, "Outer type%s:", dynamic ? " (dynamic)":"");
62638fd1498Szrj print_generic_expr (f, outer_type, TDF_SLIM);
62738fd1498Szrj if (maybe_derived_type)
62838fd1498Szrj fprintf (f, " (or a derived type)");
62938fd1498Szrj if (maybe_in_construction)
63038fd1498Szrj fprintf (f, " (maybe in construction)");
63138fd1498Szrj fprintf (f, " offset " HOST_WIDE_INT_PRINT_DEC,
63238fd1498Szrj offset);
63338fd1498Szrj }
63438fd1498Szrj if (speculative_outer_type)
63538fd1498Szrj {
63638fd1498Szrj if (outer_type || offset)
63738fd1498Szrj fprintf (f, " ");
63838fd1498Szrj fprintf (f, "Speculative outer type:");
63938fd1498Szrj print_generic_expr (f, speculative_outer_type, TDF_SLIM);
64038fd1498Szrj if (speculative_maybe_derived_type)
64138fd1498Szrj fprintf (f, " (or a derived type)");
64238fd1498Szrj fprintf (f, " at offset " HOST_WIDE_INT_PRINT_DEC,
64338fd1498Szrj speculative_offset);
64438fd1498Szrj }
64538fd1498Szrj }
64638fd1498Szrj if (newline)
64738fd1498Szrj fprintf(f, "\n");
64838fd1498Szrj }
64938fd1498Szrj
65038fd1498Szrj /* Print context to stderr. */
65138fd1498Szrj
65238fd1498Szrj void
debug()65338fd1498Szrj ipa_polymorphic_call_context::debug () const
65438fd1498Szrj {
65538fd1498Szrj dump (stderr);
65638fd1498Szrj }
65738fd1498Szrj
65838fd1498Szrj /* Stream out the context to OB. */
65938fd1498Szrj
66038fd1498Szrj void
stream_out(struct output_block * ob)66138fd1498Szrj ipa_polymorphic_call_context::stream_out (struct output_block *ob) const
66238fd1498Szrj {
66338fd1498Szrj struct bitpack_d bp = bitpack_create (ob->main_stream);
66438fd1498Szrj
66538fd1498Szrj bp_pack_value (&bp, invalid, 1);
66638fd1498Szrj bp_pack_value (&bp, maybe_in_construction, 1);
66738fd1498Szrj bp_pack_value (&bp, maybe_derived_type, 1);
66838fd1498Szrj bp_pack_value (&bp, speculative_maybe_derived_type, 1);
66938fd1498Szrj bp_pack_value (&bp, dynamic, 1);
67038fd1498Szrj bp_pack_value (&bp, outer_type != NULL, 1);
67138fd1498Szrj bp_pack_value (&bp, offset != 0, 1);
67238fd1498Szrj bp_pack_value (&bp, speculative_outer_type != NULL, 1);
67338fd1498Szrj streamer_write_bitpack (&bp);
67438fd1498Szrj
67538fd1498Szrj if (outer_type != NULL)
67638fd1498Szrj stream_write_tree (ob, outer_type, true);
67738fd1498Szrj if (offset)
67838fd1498Szrj streamer_write_hwi (ob, offset);
67938fd1498Szrj if (speculative_outer_type != NULL)
68038fd1498Szrj {
68138fd1498Szrj stream_write_tree (ob, speculative_outer_type, true);
68238fd1498Szrj streamer_write_hwi (ob, speculative_offset);
68338fd1498Szrj }
68438fd1498Szrj else
68538fd1498Szrj gcc_assert (!speculative_offset);
68638fd1498Szrj }
68738fd1498Szrj
68838fd1498Szrj /* Stream in the context from IB and DATA_IN. */
68938fd1498Szrj
69038fd1498Szrj void
stream_in(struct lto_input_block * ib,struct data_in * data_in)69138fd1498Szrj ipa_polymorphic_call_context::stream_in (struct lto_input_block *ib,
69238fd1498Szrj struct data_in *data_in)
69338fd1498Szrj {
69438fd1498Szrj struct bitpack_d bp = streamer_read_bitpack (ib);
69538fd1498Szrj
69638fd1498Szrj invalid = bp_unpack_value (&bp, 1);
69738fd1498Szrj maybe_in_construction = bp_unpack_value (&bp, 1);
69838fd1498Szrj maybe_derived_type = bp_unpack_value (&bp, 1);
69938fd1498Szrj speculative_maybe_derived_type = bp_unpack_value (&bp, 1);
70038fd1498Szrj dynamic = bp_unpack_value (&bp, 1);
70138fd1498Szrj bool outer_type_p = bp_unpack_value (&bp, 1);
70238fd1498Szrj bool offset_p = bp_unpack_value (&bp, 1);
70338fd1498Szrj bool speculative_outer_type_p = bp_unpack_value (&bp, 1);
70438fd1498Szrj
70538fd1498Szrj if (outer_type_p)
70638fd1498Szrj outer_type = stream_read_tree (ib, data_in);
70738fd1498Szrj else
70838fd1498Szrj outer_type = NULL;
70938fd1498Szrj if (offset_p)
71038fd1498Szrj offset = (HOST_WIDE_INT) streamer_read_hwi (ib);
71138fd1498Szrj else
71238fd1498Szrj offset = 0;
71338fd1498Szrj if (speculative_outer_type_p)
71438fd1498Szrj {
71538fd1498Szrj speculative_outer_type = stream_read_tree (ib, data_in);
71638fd1498Szrj speculative_offset = (HOST_WIDE_INT) streamer_read_hwi (ib);
71738fd1498Szrj }
71838fd1498Szrj else
71938fd1498Szrj {
72038fd1498Szrj speculative_outer_type = NULL;
72138fd1498Szrj speculative_offset = 0;
72238fd1498Szrj }
72338fd1498Szrj }
72438fd1498Szrj
72538fd1498Szrj /* Proudce polymorphic call context for call method of instance
72638fd1498Szrj that is located within BASE (that is assumed to be a decl) at offset OFF. */
72738fd1498Szrj
72838fd1498Szrj void
set_by_decl(tree base,HOST_WIDE_INT off)72938fd1498Szrj ipa_polymorphic_call_context::set_by_decl (tree base, HOST_WIDE_INT off)
73038fd1498Szrj {
73138fd1498Szrj gcc_assert (DECL_P (base));
73238fd1498Szrj clear_speculation ();
73338fd1498Szrj
73438fd1498Szrj if (!contains_polymorphic_type_p (TREE_TYPE (base)))
73538fd1498Szrj {
73638fd1498Szrj clear_outer_type ();
73738fd1498Szrj offset = off;
73838fd1498Szrj return;
73938fd1498Szrj }
74038fd1498Szrj outer_type = TYPE_MAIN_VARIANT (TREE_TYPE (base));
74138fd1498Szrj offset = off;
74238fd1498Szrj /* Make very conservative assumption that all objects
74338fd1498Szrj may be in construction.
74438fd1498Szrj
74538fd1498Szrj It is up to caller to revisit this via
74638fd1498Szrj get_dynamic_type or decl_maybe_in_construction_p. */
74738fd1498Szrj maybe_in_construction = true;
74838fd1498Szrj maybe_derived_type = false;
74938fd1498Szrj dynamic = false;
75038fd1498Szrj }
75138fd1498Szrj
75238fd1498Szrj /* CST is an invariant (address of decl), try to get meaningful
75338fd1498Szrj polymorphic call context for polymorphic call of method
75438fd1498Szrj if instance of OTR_TYPE that is located at offset OFF of this invariant.
75538fd1498Szrj Return FALSE if nothing meaningful can be found. */
75638fd1498Szrj
75738fd1498Szrj bool
set_by_invariant(tree cst,tree otr_type,HOST_WIDE_INT off)75838fd1498Szrj ipa_polymorphic_call_context::set_by_invariant (tree cst,
75938fd1498Szrj tree otr_type,
76038fd1498Szrj HOST_WIDE_INT off)
76138fd1498Szrj {
76238fd1498Szrj poly_int64 offset2, size, max_size;
76338fd1498Szrj bool reverse;
76438fd1498Szrj tree base;
76538fd1498Szrj
76638fd1498Szrj invalid = false;
76738fd1498Szrj off = 0;
76838fd1498Szrj clear_outer_type (otr_type);
76938fd1498Szrj
77038fd1498Szrj if (TREE_CODE (cst) != ADDR_EXPR)
77138fd1498Szrj return false;
77238fd1498Szrj
77338fd1498Szrj cst = TREE_OPERAND (cst, 0);
77438fd1498Szrj base = get_ref_base_and_extent (cst, &offset2, &size, &max_size, &reverse);
77538fd1498Szrj if (!DECL_P (base) || !known_size_p (max_size) || maybe_ne (max_size, size))
77638fd1498Szrj return false;
77738fd1498Szrj
77838fd1498Szrj /* Only type inconsistent programs can have otr_type that is
77938fd1498Szrj not part of outer type. */
78038fd1498Szrj if (otr_type && !contains_type_p (TREE_TYPE (base), off, otr_type))
78138fd1498Szrj return false;
78238fd1498Szrj
78338fd1498Szrj set_by_decl (base, off);
78438fd1498Szrj return true;
78538fd1498Szrj }
78638fd1498Szrj
78738fd1498Szrj /* See if OP is SSA name initialized as a copy or by single assignment.
78838fd1498Szrj If so, walk the SSA graph up. Because simple PHI conditional is considered
78938fd1498Szrj copy, GLOBAL_VISITED may be used to avoid infinite loop walking the SSA
79038fd1498Szrj graph. */
79138fd1498Szrj
79238fd1498Szrj static tree
79338fd1498Szrj walk_ssa_copies (tree op, hash_set<tree> **global_visited = NULL)
79438fd1498Szrj {
79538fd1498Szrj hash_set <tree> *visited = NULL;
79638fd1498Szrj STRIP_NOPS (op);
79738fd1498Szrj while (TREE_CODE (op) == SSA_NAME
79838fd1498Szrj && !SSA_NAME_IS_DEFAULT_DEF (op)
79938fd1498Szrj /* We might be called via fold_stmt during cfgcleanup where
80038fd1498Szrj SSA form need not be up-to-date. */
80138fd1498Szrj && !name_registered_for_update_p (op)
80238fd1498Szrj && (gimple_assign_single_p (SSA_NAME_DEF_STMT (op))
80338fd1498Szrj || gimple_code (SSA_NAME_DEF_STMT (op)) == GIMPLE_PHI))
80438fd1498Szrj {
80538fd1498Szrj if (global_visited)
80638fd1498Szrj {
80738fd1498Szrj if (!*global_visited)
80838fd1498Szrj *global_visited = new hash_set<tree>;
80938fd1498Szrj if ((*global_visited)->add (op))
81038fd1498Szrj goto done;
81138fd1498Szrj }
81238fd1498Szrj else
81338fd1498Szrj {
81438fd1498Szrj if (!visited)
81538fd1498Szrj visited = new hash_set<tree>;
81638fd1498Szrj if (visited->add (op))
81738fd1498Szrj goto done;
81838fd1498Szrj }
81938fd1498Szrj /* Special case
82038fd1498Szrj if (ptr == 0)
82138fd1498Szrj ptr = 0;
82238fd1498Szrj else
82338fd1498Szrj ptr = ptr.foo;
82438fd1498Szrj This pattern is implicitly produced for casts to non-primary
82538fd1498Szrj bases. When doing context analysis, we do not really care
82638fd1498Szrj about the case pointer is NULL, because the call will be
82738fd1498Szrj undefined anyway. */
82838fd1498Szrj if (gimple_code (SSA_NAME_DEF_STMT (op)) == GIMPLE_PHI)
82938fd1498Szrj {
83038fd1498Szrj gimple *phi = SSA_NAME_DEF_STMT (op);
83138fd1498Szrj
83238fd1498Szrj if (gimple_phi_num_args (phi) > 2)
83338fd1498Szrj goto done;
83438fd1498Szrj if (gimple_phi_num_args (phi) == 1)
83538fd1498Szrj op = gimple_phi_arg_def (phi, 0);
83638fd1498Szrj else if (integer_zerop (gimple_phi_arg_def (phi, 0)))
83738fd1498Szrj op = gimple_phi_arg_def (phi, 1);
83838fd1498Szrj else if (integer_zerop (gimple_phi_arg_def (phi, 1)))
83938fd1498Szrj op = gimple_phi_arg_def (phi, 0);
84038fd1498Szrj else
84138fd1498Szrj goto done;
84238fd1498Szrj }
84338fd1498Szrj else
84438fd1498Szrj {
84538fd1498Szrj if (gimple_assign_load_p (SSA_NAME_DEF_STMT (op)))
84638fd1498Szrj goto done;
84738fd1498Szrj op = gimple_assign_rhs1 (SSA_NAME_DEF_STMT (op));
84838fd1498Szrj }
84938fd1498Szrj STRIP_NOPS (op);
85038fd1498Szrj }
85138fd1498Szrj done:
85238fd1498Szrj if (visited)
85338fd1498Szrj delete (visited);
85438fd1498Szrj return op;
85538fd1498Szrj }
85638fd1498Szrj
85738fd1498Szrj /* Create polymorphic call context from IP invariant CST.
85838fd1498Szrj This is typically &global_var.
85938fd1498Szrj OTR_TYPE specify type of polymorphic call or NULL if unknown, OFF
86038fd1498Szrj is offset of call. */
86138fd1498Szrj
ipa_polymorphic_call_context(tree cst,tree otr_type,HOST_WIDE_INT off)86238fd1498Szrj ipa_polymorphic_call_context::ipa_polymorphic_call_context (tree cst,
86338fd1498Szrj tree otr_type,
86438fd1498Szrj HOST_WIDE_INT off)
86538fd1498Szrj {
86638fd1498Szrj clear_speculation ();
86738fd1498Szrj set_by_invariant (cst, otr_type, off);
86838fd1498Szrj }
86938fd1498Szrj
87038fd1498Szrj /* Build context for pointer REF contained in FNDECL at statement STMT.
87138fd1498Szrj if INSTANCE is non-NULL, return pointer to the object described by
87238fd1498Szrj the context or DECL where context is contained in. */
87338fd1498Szrj
ipa_polymorphic_call_context(tree fndecl,tree ref,gimple * stmt,tree * instance)87438fd1498Szrj ipa_polymorphic_call_context::ipa_polymorphic_call_context (tree fndecl,
87538fd1498Szrj tree ref,
87638fd1498Szrj gimple *stmt,
87738fd1498Szrj tree *instance)
87838fd1498Szrj {
87938fd1498Szrj tree otr_type = NULL;
88038fd1498Szrj tree base_pointer;
88138fd1498Szrj hash_set <tree> *visited = NULL;
88238fd1498Szrj
88338fd1498Szrj if (TREE_CODE (ref) == OBJ_TYPE_REF)
88438fd1498Szrj {
88538fd1498Szrj otr_type = obj_type_ref_class (ref);
88638fd1498Szrj base_pointer = OBJ_TYPE_REF_OBJECT (ref);
88738fd1498Szrj }
88838fd1498Szrj else
88938fd1498Szrj base_pointer = ref;
89038fd1498Szrj
89138fd1498Szrj /* Set up basic info in case we find nothing interesting in the analysis. */
89238fd1498Szrj clear_speculation ();
89338fd1498Szrj clear_outer_type (otr_type);
89438fd1498Szrj invalid = false;
89538fd1498Szrj
89638fd1498Szrj /* Walk SSA for outer object. */
89738fd1498Szrj while (true)
89838fd1498Szrj {
89938fd1498Szrj base_pointer = walk_ssa_copies (base_pointer, &visited);
90038fd1498Szrj if (TREE_CODE (base_pointer) == ADDR_EXPR)
90138fd1498Szrj {
90238fd1498Szrj HOST_WIDE_INT offset2, size;
90338fd1498Szrj bool reverse;
90438fd1498Szrj tree base
90538fd1498Szrj = get_ref_base_and_extent_hwi (TREE_OPERAND (base_pointer, 0),
90638fd1498Szrj &offset2, &size, &reverse);
90738fd1498Szrj if (!base)
90838fd1498Szrj break;
90938fd1498Szrj
91038fd1498Szrj combine_speculation_with (TYPE_MAIN_VARIANT (TREE_TYPE (base)),
91138fd1498Szrj offset + offset2,
91238fd1498Szrj true,
91338fd1498Szrj NULL /* Do not change outer type. */);
91438fd1498Szrj
91538fd1498Szrj /* If this is a varying address, punt. */
91638fd1498Szrj if (TREE_CODE (base) == MEM_REF || DECL_P (base))
91738fd1498Szrj {
91838fd1498Szrj /* We found dereference of a pointer. Type of the pointer
91938fd1498Szrj and MEM_REF is meaningless, but we can look futher. */
92038fd1498Szrj offset_int mem_offset;
92138fd1498Szrj if (TREE_CODE (base) == MEM_REF
92238fd1498Szrj && mem_ref_offset (base).is_constant (&mem_offset))
92338fd1498Szrj {
92438fd1498Szrj offset_int o = mem_offset * BITS_PER_UNIT;
92538fd1498Szrj o += offset;
92638fd1498Szrj o += offset2;
92738fd1498Szrj if (!wi::fits_shwi_p (o))
92838fd1498Szrj break;
92938fd1498Szrj base_pointer = TREE_OPERAND (base, 0);
93038fd1498Szrj offset = o.to_shwi ();
93138fd1498Szrj outer_type = NULL;
93238fd1498Szrj }
93338fd1498Szrj /* We found base object. In this case the outer_type
93438fd1498Szrj is known. */
93538fd1498Szrj else if (DECL_P (base))
93638fd1498Szrj {
93738fd1498Szrj if (visited)
93838fd1498Szrj delete (visited);
93938fd1498Szrj /* Only type inconsistent programs can have otr_type that is
94038fd1498Szrj not part of outer type. */
94138fd1498Szrj if (otr_type
94238fd1498Szrj && !contains_type_p (TREE_TYPE (base),
94338fd1498Szrj offset + offset2, otr_type))
94438fd1498Szrj {
94538fd1498Szrj invalid = true;
94638fd1498Szrj if (instance)
94738fd1498Szrj *instance = base_pointer;
94838fd1498Szrj return;
94938fd1498Szrj }
95038fd1498Szrj set_by_decl (base, offset + offset2);
95138fd1498Szrj if (outer_type && maybe_in_construction && stmt)
95238fd1498Szrj maybe_in_construction
95338fd1498Szrj = decl_maybe_in_construction_p (base,
95438fd1498Szrj outer_type,
95538fd1498Szrj stmt,
95638fd1498Szrj fndecl);
95738fd1498Szrj if (instance)
95838fd1498Szrj *instance = base;
95938fd1498Szrj return;
96038fd1498Szrj }
96138fd1498Szrj else
96238fd1498Szrj break;
96338fd1498Szrj }
96438fd1498Szrj else
96538fd1498Szrj break;
96638fd1498Szrj }
96738fd1498Szrj else if (TREE_CODE (base_pointer) == POINTER_PLUS_EXPR
96838fd1498Szrj && TREE_CODE (TREE_OPERAND (base_pointer, 1)) == INTEGER_CST)
96938fd1498Szrj {
97038fd1498Szrj offset_int o
97138fd1498Szrj = offset_int::from (wi::to_wide (TREE_OPERAND (base_pointer, 1)),
97238fd1498Szrj SIGNED);
97338fd1498Szrj o *= BITS_PER_UNIT;
97438fd1498Szrj o += offset;
97538fd1498Szrj if (!wi::fits_shwi_p (o))
97638fd1498Szrj break;
97738fd1498Szrj offset = o.to_shwi ();
97838fd1498Szrj base_pointer = TREE_OPERAND (base_pointer, 0);
97938fd1498Szrj }
98038fd1498Szrj else
98138fd1498Szrj break;
98238fd1498Szrj }
98338fd1498Szrj
98438fd1498Szrj if (visited)
98538fd1498Szrj delete (visited);
98638fd1498Szrj
98738fd1498Szrj /* Try to determine type of the outer object. */
98838fd1498Szrj if (TREE_CODE (base_pointer) == SSA_NAME
98938fd1498Szrj && SSA_NAME_IS_DEFAULT_DEF (base_pointer)
99038fd1498Szrj && TREE_CODE (SSA_NAME_VAR (base_pointer)) == PARM_DECL)
99138fd1498Szrj {
99238fd1498Szrj /* See if parameter is THIS pointer of a method. */
99338fd1498Szrj if (TREE_CODE (TREE_TYPE (fndecl)) == METHOD_TYPE
99438fd1498Szrj && SSA_NAME_VAR (base_pointer) == DECL_ARGUMENTS (fndecl))
99538fd1498Szrj {
99638fd1498Szrj outer_type
99738fd1498Szrj = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (base_pointer)));
998*58e805e6Szrj cgraph_node *node = cgraph_node::get (current_function_decl);
99938fd1498Szrj gcc_assert (TREE_CODE (outer_type) == RECORD_TYPE
100038fd1498Szrj || TREE_CODE (outer_type) == UNION_TYPE);
100138fd1498Szrj
1002*58e805e6Szrj /* Handle the case we inlined into a thunk. In this case
1003*58e805e6Szrj thunk has THIS pointer of type bar, but it really receives
1004*58e805e6Szrj address to its base type foo which sits in bar at
1005*58e805e6Szrj 0-thunk.fixed_offset. It starts with code that adds
1006*58e805e6Szrj think.fixed_offset to the pointer to compensate for this.
1007*58e805e6Szrj
1008*58e805e6Szrj Because we walked all the way to the begining of thunk, we now
1009*58e805e6Szrj see pointer &bar-thunk.fixed_offset and need to compensate
1010*58e805e6Szrj for it. */
1011*58e805e6Szrj if (node->thunk.fixed_offset)
1012*58e805e6Szrj offset -= node->thunk.fixed_offset * BITS_PER_UNIT;
1013*58e805e6Szrj
101438fd1498Szrj /* Dynamic casting has possibly upcasted the type
101538fd1498Szrj in the hiearchy. In this case outer type is less
101638fd1498Szrj informative than inner type and we should forget
101738fd1498Szrj about it. */
101838fd1498Szrj if ((otr_type
101938fd1498Szrj && !contains_type_p (outer_type, offset,
102038fd1498Szrj otr_type))
1021*58e805e6Szrj || !contains_polymorphic_type_p (outer_type)
1022*58e805e6Szrj /* If we compile thunk with virtual offset, the THIS pointer
1023*58e805e6Szrj is adjusted by unknown value. We can't thus use outer info
1024*58e805e6Szrj at all. */
1025*58e805e6Szrj || node->thunk.virtual_offset_p)
102638fd1498Szrj {
102738fd1498Szrj outer_type = NULL;
102838fd1498Szrj if (instance)
102938fd1498Szrj *instance = base_pointer;
103038fd1498Szrj return;
103138fd1498Szrj }
103238fd1498Szrj
103338fd1498Szrj dynamic = true;
103438fd1498Szrj
103538fd1498Szrj /* If the function is constructor or destructor, then
103638fd1498Szrj the type is possibly in construction, but we know
103738fd1498Szrj it is not derived type. */
103838fd1498Szrj if (DECL_CXX_CONSTRUCTOR_P (fndecl)
103938fd1498Szrj || DECL_CXX_DESTRUCTOR_P (fndecl))
104038fd1498Szrj {
104138fd1498Szrj maybe_in_construction = true;
104238fd1498Szrj maybe_derived_type = false;
104338fd1498Szrj }
104438fd1498Szrj else
104538fd1498Szrj {
104638fd1498Szrj maybe_derived_type = true;
104738fd1498Szrj maybe_in_construction = false;
104838fd1498Szrj }
104938fd1498Szrj if (instance)
1050*58e805e6Szrj {
1051*58e805e6Szrj /* If method is expanded thunk, we need to apply thunk offset
1052*58e805e6Szrj to instance pointer. */
1053*58e805e6Szrj if (node->thunk.virtual_offset_p
1054*58e805e6Szrj || node->thunk.fixed_offset)
1055*58e805e6Szrj *instance = NULL;
1056*58e805e6Szrj else
105738fd1498Szrj *instance = base_pointer;
1058*58e805e6Szrj }
105938fd1498Szrj return;
106038fd1498Szrj }
106138fd1498Szrj /* Non-PODs passed by value are really passed by invisible
106238fd1498Szrj reference. In this case we also know the type of the
106338fd1498Szrj object. */
106438fd1498Szrj if (DECL_BY_REFERENCE (SSA_NAME_VAR (base_pointer)))
106538fd1498Szrj {
106638fd1498Szrj outer_type
106738fd1498Szrj = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (base_pointer)));
106838fd1498Szrj /* Only type inconsistent programs can have otr_type that is
106938fd1498Szrj not part of outer type. */
107038fd1498Szrj if (otr_type && !contains_type_p (outer_type, offset,
107138fd1498Szrj otr_type))
107238fd1498Szrj {
107338fd1498Szrj invalid = true;
107438fd1498Szrj if (instance)
107538fd1498Szrj *instance = base_pointer;
107638fd1498Szrj return;
107738fd1498Szrj }
107838fd1498Szrj /* Non-polymorphic types have no interest for us. */
107938fd1498Szrj else if (!otr_type && !contains_polymorphic_type_p (outer_type))
108038fd1498Szrj {
108138fd1498Szrj outer_type = NULL;
108238fd1498Szrj if (instance)
108338fd1498Szrj *instance = base_pointer;
108438fd1498Szrj return;
108538fd1498Szrj }
108638fd1498Szrj maybe_derived_type = false;
108738fd1498Szrj maybe_in_construction = false;
108838fd1498Szrj if (instance)
108938fd1498Szrj *instance = base_pointer;
109038fd1498Szrj return;
109138fd1498Szrj }
109238fd1498Szrj }
109338fd1498Szrj
109438fd1498Szrj tree base_type = TREE_TYPE (base_pointer);
109538fd1498Szrj
109638fd1498Szrj if (TREE_CODE (base_pointer) == SSA_NAME
109738fd1498Szrj && SSA_NAME_IS_DEFAULT_DEF (base_pointer)
109838fd1498Szrj && !(TREE_CODE (SSA_NAME_VAR (base_pointer)) == PARM_DECL
109938fd1498Szrj || TREE_CODE (SSA_NAME_VAR (base_pointer)) == RESULT_DECL))
110038fd1498Szrj {
110138fd1498Szrj invalid = true;
110238fd1498Szrj if (instance)
110338fd1498Szrj *instance = base_pointer;
110438fd1498Szrj return;
110538fd1498Szrj }
110638fd1498Szrj if (TREE_CODE (base_pointer) == SSA_NAME
110738fd1498Szrj && SSA_NAME_DEF_STMT (base_pointer)
110838fd1498Szrj && gimple_assign_single_p (SSA_NAME_DEF_STMT (base_pointer)))
110938fd1498Szrj base_type = TREE_TYPE (gimple_assign_rhs1
111038fd1498Szrj (SSA_NAME_DEF_STMT (base_pointer)));
111138fd1498Szrj
111238fd1498Szrj if (base_type && POINTER_TYPE_P (base_type))
111338fd1498Szrj combine_speculation_with (TYPE_MAIN_VARIANT (TREE_TYPE (base_type)),
111438fd1498Szrj offset,
111538fd1498Szrj true, NULL /* Do not change type here */);
111638fd1498Szrj /* TODO: There are multiple ways to derive a type. For instance
111738fd1498Szrj if BASE_POINTER is passed to an constructor call prior our refernece.
111838fd1498Szrj We do not make this type of flow sensitive analysis yet. */
111938fd1498Szrj if (instance)
112038fd1498Szrj *instance = base_pointer;
112138fd1498Szrj return;
112238fd1498Szrj }
112338fd1498Szrj
112438fd1498Szrj /* Structure to be passed in between detect_type_change and
112538fd1498Szrj check_stmt_for_type_change. */
112638fd1498Szrj
112738fd1498Szrj struct type_change_info
112838fd1498Szrj {
112938fd1498Szrj /* Offset into the object where there is the virtual method pointer we are
113038fd1498Szrj looking for. */
113138fd1498Szrj HOST_WIDE_INT offset;
113238fd1498Szrj /* The declaration or SSA_NAME pointer of the base that we are checking for
113338fd1498Szrj type change. */
113438fd1498Szrj tree instance;
113538fd1498Szrj /* The reference to virtual table pointer used. */
113638fd1498Szrj tree vtbl_ptr_ref;
113738fd1498Szrj tree otr_type;
113838fd1498Szrj /* If we actually can tell the type that the object has changed to, it is
113938fd1498Szrj stored in this field. Otherwise it remains NULL_TREE. */
114038fd1498Szrj tree known_current_type;
114138fd1498Szrj HOST_WIDE_INT known_current_offset;
114238fd1498Szrj
114338fd1498Szrj /* Set to nonzero if we possibly missed some dynamic type changes and we
114438fd1498Szrj should consider the set to be speculative. */
114538fd1498Szrj unsigned speculative;
114638fd1498Szrj
114738fd1498Szrj /* Set to true if dynamic type change has been detected. */
114838fd1498Szrj bool type_maybe_changed;
114938fd1498Szrj /* Set to true if multiple types have been encountered. known_current_type
115038fd1498Szrj must be disregarded in that case. */
115138fd1498Szrj bool multiple_types_encountered;
115238fd1498Szrj bool seen_unanalyzed_store;
115338fd1498Szrj };
115438fd1498Szrj
115538fd1498Szrj /* Return true if STMT is not call and can modify a virtual method table pointer.
115638fd1498Szrj We take advantage of fact that vtable stores must appear within constructor
115738fd1498Szrj and destructor functions. */
115838fd1498Szrj
115938fd1498Szrj static bool
noncall_stmt_may_be_vtbl_ptr_store(gimple * stmt)116038fd1498Szrj noncall_stmt_may_be_vtbl_ptr_store (gimple *stmt)
116138fd1498Szrj {
116238fd1498Szrj if (is_gimple_assign (stmt))
116338fd1498Szrj {
116438fd1498Szrj tree lhs = gimple_assign_lhs (stmt);
116538fd1498Szrj
116638fd1498Szrj if (gimple_clobber_p (stmt))
116738fd1498Szrj return false;
116838fd1498Szrj if (!AGGREGATE_TYPE_P (TREE_TYPE (lhs)))
116938fd1498Szrj {
117038fd1498Szrj if (flag_strict_aliasing
117138fd1498Szrj && !POINTER_TYPE_P (TREE_TYPE (lhs)))
117238fd1498Szrj return false;
117338fd1498Szrj
117438fd1498Szrj if (TREE_CODE (lhs) == COMPONENT_REF
117538fd1498Szrj && !DECL_VIRTUAL_P (TREE_OPERAND (lhs, 1)))
117638fd1498Szrj return false;
117738fd1498Szrj /* In the future we might want to use get_ref_base_and_extent to find
117838fd1498Szrj if there is a field corresponding to the offset and if so, proceed
117938fd1498Szrj almost like if it was a component ref. */
118038fd1498Szrj }
118138fd1498Szrj }
118238fd1498Szrj
118338fd1498Szrj /* Code unification may mess with inline stacks. */
118438fd1498Szrj if (cfun->after_inlining)
118538fd1498Szrj return true;
118638fd1498Szrj
118738fd1498Szrj /* Walk the inline stack and watch out for ctors/dtors.
118838fd1498Szrj TODO: Maybe we can require the store to appear in toplevel
118938fd1498Szrj block of CTOR/DTOR. */
119038fd1498Szrj for (tree block = gimple_block (stmt); block && TREE_CODE (block) == BLOCK;
119138fd1498Szrj block = BLOCK_SUPERCONTEXT (block))
119238fd1498Szrj if (BLOCK_ABSTRACT_ORIGIN (block)
119338fd1498Szrj && TREE_CODE (block_ultimate_origin (block)) == FUNCTION_DECL)
119438fd1498Szrj return inlined_polymorphic_ctor_dtor_block_p (block, false);
119538fd1498Szrj return (TREE_CODE (TREE_TYPE (current_function_decl)) == METHOD_TYPE
119638fd1498Szrj && (DECL_CXX_CONSTRUCTOR_P (current_function_decl)
119738fd1498Szrj || DECL_CXX_DESTRUCTOR_P (current_function_decl)));
119838fd1498Szrj }
119938fd1498Szrj
120038fd1498Szrj /* If STMT can be proved to be an assignment to the virtual method table
120138fd1498Szrj pointer of ANALYZED_OBJ and the type associated with the new table
120238fd1498Szrj identified, return the type. Otherwise return NULL_TREE if type changes
120338fd1498Szrj in unknown way or ERROR_MARK_NODE if type is unchanged. */
120438fd1498Szrj
120538fd1498Szrj static tree
extr_type_from_vtbl_ptr_store(gimple * stmt,struct type_change_info * tci,HOST_WIDE_INT * type_offset)120638fd1498Szrj extr_type_from_vtbl_ptr_store (gimple *stmt, struct type_change_info *tci,
120738fd1498Szrj HOST_WIDE_INT *type_offset)
120838fd1498Szrj {
120938fd1498Szrj poly_int64 offset, size, max_size;
121038fd1498Szrj tree lhs, rhs, base;
121138fd1498Szrj bool reverse;
121238fd1498Szrj
121338fd1498Szrj if (!gimple_assign_single_p (stmt))
121438fd1498Szrj return NULL_TREE;
121538fd1498Szrj
121638fd1498Szrj lhs = gimple_assign_lhs (stmt);
121738fd1498Szrj rhs = gimple_assign_rhs1 (stmt);
121838fd1498Szrj if (TREE_CODE (lhs) != COMPONENT_REF
121938fd1498Szrj || !DECL_VIRTUAL_P (TREE_OPERAND (lhs, 1)))
122038fd1498Szrj {
122138fd1498Szrj if (dump_file)
122238fd1498Szrj fprintf (dump_file, " LHS is not virtual table.\n");
122338fd1498Szrj return NULL_TREE;
122438fd1498Szrj }
122538fd1498Szrj
122638fd1498Szrj if (tci->vtbl_ptr_ref && operand_equal_p (lhs, tci->vtbl_ptr_ref, 0))
122738fd1498Szrj ;
122838fd1498Szrj else
122938fd1498Szrj {
123038fd1498Szrj base = get_ref_base_and_extent (lhs, &offset, &size, &max_size, &reverse);
123138fd1498Szrj if (DECL_P (tci->instance))
123238fd1498Szrj {
123338fd1498Szrj if (base != tci->instance)
123438fd1498Szrj {
123538fd1498Szrj if (dump_file)
123638fd1498Szrj {
123738fd1498Szrj fprintf (dump_file, " base:");
123838fd1498Szrj print_generic_expr (dump_file, base, TDF_SLIM);
123938fd1498Szrj fprintf (dump_file, " does not match instance:");
124038fd1498Szrj print_generic_expr (dump_file, tci->instance, TDF_SLIM);
124138fd1498Szrj fprintf (dump_file, "\n");
124238fd1498Szrj }
124338fd1498Szrj return NULL_TREE;
124438fd1498Szrj }
124538fd1498Szrj }
124638fd1498Szrj else if (TREE_CODE (base) == MEM_REF)
124738fd1498Szrj {
124838fd1498Szrj if (!operand_equal_p (tci->instance, TREE_OPERAND (base, 0), 0))
124938fd1498Szrj {
125038fd1498Szrj if (dump_file)
125138fd1498Szrj {
125238fd1498Szrj fprintf (dump_file, " base mem ref:");
125338fd1498Szrj print_generic_expr (dump_file, base, TDF_SLIM);
125438fd1498Szrj fprintf (dump_file, " does not match instance:");
125538fd1498Szrj print_generic_expr (dump_file, tci->instance, TDF_SLIM);
125638fd1498Szrj fprintf (dump_file, "\n");
125738fd1498Szrj }
125838fd1498Szrj return NULL_TREE;
125938fd1498Szrj }
126038fd1498Szrj if (!integer_zerop (TREE_OPERAND (base, 1)))
126138fd1498Szrj {
126238fd1498Szrj if (!tree_fits_shwi_p (TREE_OPERAND (base, 1)))
126338fd1498Szrj {
126438fd1498Szrj if (dump_file)
126538fd1498Szrj {
126638fd1498Szrj fprintf (dump_file, " base mem ref:");
126738fd1498Szrj print_generic_expr (dump_file, base, TDF_SLIM);
126838fd1498Szrj fprintf (dump_file, " has non-representable offset:");
126938fd1498Szrj print_generic_expr (dump_file, tci->instance, TDF_SLIM);
127038fd1498Szrj fprintf (dump_file, "\n");
127138fd1498Szrj }
127238fd1498Szrj return NULL_TREE;
127338fd1498Szrj }
127438fd1498Szrj else
127538fd1498Szrj offset += tree_to_shwi (TREE_OPERAND (base, 1)) * BITS_PER_UNIT;
127638fd1498Szrj }
127738fd1498Szrj }
127838fd1498Szrj else if (!operand_equal_p (tci->instance, base, 0)
127938fd1498Szrj || tci->offset)
128038fd1498Szrj {
128138fd1498Szrj if (dump_file)
128238fd1498Szrj {
128338fd1498Szrj fprintf (dump_file, " base:");
128438fd1498Szrj print_generic_expr (dump_file, base, TDF_SLIM);
128538fd1498Szrj fprintf (dump_file, " does not match instance:");
128638fd1498Szrj print_generic_expr (dump_file, tci->instance, TDF_SLIM);
128738fd1498Szrj fprintf (dump_file, " with offset %i\n", (int)tci->offset);
128838fd1498Szrj }
128938fd1498Szrj return tci->offset > POINTER_SIZE ? error_mark_node : NULL_TREE;
129038fd1498Szrj }
129138fd1498Szrj if (maybe_ne (offset, tci->offset)
129238fd1498Szrj || maybe_ne (size, POINTER_SIZE)
129338fd1498Szrj || maybe_ne (max_size, POINTER_SIZE))
129438fd1498Szrj {
129538fd1498Szrj if (dump_file)
129638fd1498Szrj {
129738fd1498Szrj fprintf (dump_file, " wrong offset ");
129838fd1498Szrj print_dec (offset, dump_file);
129938fd1498Szrj fprintf (dump_file, "!=%i or size ", (int) tci->offset);
130038fd1498Szrj print_dec (size, dump_file);
130138fd1498Szrj fprintf (dump_file, "\n");
130238fd1498Szrj }
130338fd1498Szrj return (known_le (offset + POINTER_SIZE, tci->offset)
130438fd1498Szrj || (known_size_p (max_size)
130538fd1498Szrj && known_gt (tci->offset + POINTER_SIZE,
130638fd1498Szrj offset + max_size))
130738fd1498Szrj ? error_mark_node : NULL);
130838fd1498Szrj }
130938fd1498Szrj }
131038fd1498Szrj
131138fd1498Szrj tree vtable;
131238fd1498Szrj unsigned HOST_WIDE_INT offset2;
131338fd1498Szrj
131438fd1498Szrj if (!vtable_pointer_value_to_vtable (rhs, &vtable, &offset2))
131538fd1498Szrj {
131638fd1498Szrj if (dump_file)
131738fd1498Szrj fprintf (dump_file, " Failed to lookup binfo\n");
131838fd1498Szrj return NULL;
131938fd1498Szrj }
132038fd1498Szrj
132138fd1498Szrj tree binfo = subbinfo_with_vtable_at_offset (TYPE_BINFO (DECL_CONTEXT (vtable)),
132238fd1498Szrj offset2, vtable);
132338fd1498Szrj if (!binfo)
132438fd1498Szrj {
132538fd1498Szrj if (dump_file)
132638fd1498Szrj fprintf (dump_file, " Construction vtable used\n");
132738fd1498Szrj /* FIXME: We should suport construction contexts. */
132838fd1498Szrj return NULL;
132938fd1498Szrj }
133038fd1498Szrj
133138fd1498Szrj *type_offset = tree_to_shwi (BINFO_OFFSET (binfo)) * BITS_PER_UNIT;
133238fd1498Szrj return DECL_CONTEXT (vtable);
133338fd1498Szrj }
133438fd1498Szrj
133538fd1498Szrj /* Record dynamic type change of TCI to TYPE. */
133638fd1498Szrj
133738fd1498Szrj static void
record_known_type(struct type_change_info * tci,tree type,HOST_WIDE_INT offset)133838fd1498Szrj record_known_type (struct type_change_info *tci, tree type, HOST_WIDE_INT offset)
133938fd1498Szrj {
134038fd1498Szrj if (dump_file)
134138fd1498Szrj {
134238fd1498Szrj if (type)
134338fd1498Szrj {
134438fd1498Szrj fprintf (dump_file, " Recording type: ");
134538fd1498Szrj print_generic_expr (dump_file, type, TDF_SLIM);
134638fd1498Szrj fprintf (dump_file, " at offset %i\n", (int)offset);
134738fd1498Szrj }
134838fd1498Szrj else
134938fd1498Szrj fprintf (dump_file, " Recording unknown type\n");
135038fd1498Szrj }
135138fd1498Szrj
135238fd1498Szrj /* If we found a constructor of type that is not polymorphic or
135338fd1498Szrj that may contain the type in question as a field (not as base),
135438fd1498Szrj restrict to the inner class first to make type matching bellow
135538fd1498Szrj happier. */
135638fd1498Szrj if (type
135738fd1498Szrj && (offset
135838fd1498Szrj || (TREE_CODE (type) != RECORD_TYPE
135938fd1498Szrj || !TYPE_BINFO (type)
136038fd1498Szrj || !polymorphic_type_binfo_p (TYPE_BINFO (type)))))
136138fd1498Szrj {
136238fd1498Szrj ipa_polymorphic_call_context context;
136338fd1498Szrj
136438fd1498Szrj context.offset = offset;
136538fd1498Szrj context.outer_type = type;
136638fd1498Szrj context.maybe_in_construction = false;
136738fd1498Szrj context.maybe_derived_type = false;
136838fd1498Szrj context.dynamic = true;
136938fd1498Szrj /* If we failed to find the inner type, we know that the call
137038fd1498Szrj would be undefined for type produced here. */
137138fd1498Szrj if (!context.restrict_to_inner_class (tci->otr_type))
137238fd1498Szrj {
137338fd1498Szrj if (dump_file)
137438fd1498Szrj fprintf (dump_file, " Ignoring; does not contain otr_type\n");
137538fd1498Szrj return;
137638fd1498Szrj }
137738fd1498Szrj /* Watch for case we reached an POD type and anticipate placement
137838fd1498Szrj new. */
137938fd1498Szrj if (!context.maybe_derived_type)
138038fd1498Szrj {
138138fd1498Szrj type = context.outer_type;
138238fd1498Szrj offset = context.offset;
138338fd1498Szrj }
138438fd1498Szrj }
138538fd1498Szrj if (tci->type_maybe_changed
138638fd1498Szrj && (!types_same_for_odr (type, tci->known_current_type)
138738fd1498Szrj || offset != tci->known_current_offset))
138838fd1498Szrj tci->multiple_types_encountered = true;
138938fd1498Szrj tci->known_current_type = TYPE_MAIN_VARIANT (type);
139038fd1498Szrj tci->known_current_offset = offset;
139138fd1498Szrj tci->type_maybe_changed = true;
139238fd1498Szrj }
139338fd1498Szrj
139438fd1498Szrj
139538fd1498Szrj /* The maximum number of may-defs we visit when looking for a must-def
139638fd1498Szrj that changes the dynamic type in check_stmt_for_type_change. Tuned
139738fd1498Szrj after the PR12392 testcase which unlimited spends 40% time within
139838fd1498Szrj these alias walks and 8% with the following limit. */
139938fd1498Szrj
140038fd1498Szrj static inline bool
csftc_abort_walking_p(unsigned speculative)140138fd1498Szrj csftc_abort_walking_p (unsigned speculative)
140238fd1498Szrj {
140338fd1498Szrj unsigned max = PARAM_VALUE (PARAM_MAX_SPECULATIVE_DEVIRT_MAYDEFS);
140438fd1498Szrj return speculative > max ? true : false;
140538fd1498Szrj }
140638fd1498Szrj
140738fd1498Szrj /* Callback of walk_aliased_vdefs and a helper function for
140838fd1498Szrj detect_type_change to check whether a particular statement may modify
140938fd1498Szrj the virtual table pointer, and if possible also determine the new type of
141038fd1498Szrj the (sub-)object. It stores its result into DATA, which points to a
141138fd1498Szrj type_change_info structure. */
141238fd1498Szrj
141338fd1498Szrj static bool
check_stmt_for_type_change(ao_ref * ao ATTRIBUTE_UNUSED,tree vdef,void * data)141438fd1498Szrj check_stmt_for_type_change (ao_ref *ao ATTRIBUTE_UNUSED, tree vdef, void *data)
141538fd1498Szrj {
141638fd1498Szrj gimple *stmt = SSA_NAME_DEF_STMT (vdef);
141738fd1498Szrj struct type_change_info *tci = (struct type_change_info *) data;
141838fd1498Szrj tree fn;
141938fd1498Szrj
142038fd1498Szrj /* If we already gave up, just terminate the rest of walk. */
142138fd1498Szrj if (tci->multiple_types_encountered)
142238fd1498Szrj return true;
142338fd1498Szrj
142438fd1498Szrj if (is_gimple_call (stmt))
142538fd1498Szrj {
142638fd1498Szrj if (gimple_call_flags (stmt) & (ECF_CONST | ECF_PURE))
142738fd1498Szrj return false;
142838fd1498Szrj
142938fd1498Szrj /* Check for a constructor call. */
143038fd1498Szrj if ((fn = gimple_call_fndecl (stmt)) != NULL_TREE
143138fd1498Szrj && DECL_CXX_CONSTRUCTOR_P (fn)
143238fd1498Szrj && TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE
143338fd1498Szrj && gimple_call_num_args (stmt))
143438fd1498Szrj {
143538fd1498Szrj tree op = walk_ssa_copies (gimple_call_arg (stmt, 0));
143638fd1498Szrj tree type = TYPE_METHOD_BASETYPE (TREE_TYPE (fn));
143738fd1498Szrj HOST_WIDE_INT offset = 0;
143838fd1498Szrj bool reverse;
143938fd1498Szrj
144038fd1498Szrj if (dump_file)
144138fd1498Szrj {
144238fd1498Szrj fprintf (dump_file, " Checking constructor call: ");
144338fd1498Szrj print_gimple_stmt (dump_file, stmt, 0);
144438fd1498Szrj }
144538fd1498Szrj
144638fd1498Szrj /* See if THIS parameter seems like instance pointer. */
144738fd1498Szrj if (TREE_CODE (op) == ADDR_EXPR)
144838fd1498Szrj {
144938fd1498Szrj HOST_WIDE_INT size;
145038fd1498Szrj op = get_ref_base_and_extent_hwi (TREE_OPERAND (op, 0),
145138fd1498Szrj &offset, &size, &reverse);
145238fd1498Szrj if (!op)
145338fd1498Szrj {
145438fd1498Szrj tci->speculative++;
145538fd1498Szrj return csftc_abort_walking_p (tci->speculative);
145638fd1498Szrj }
145738fd1498Szrj if (TREE_CODE (op) == MEM_REF)
145838fd1498Szrj {
145938fd1498Szrj if (!tree_fits_shwi_p (TREE_OPERAND (op, 1)))
146038fd1498Szrj {
146138fd1498Szrj tci->speculative++;
146238fd1498Szrj return csftc_abort_walking_p (tci->speculative);
146338fd1498Szrj }
146438fd1498Szrj offset += tree_to_shwi (TREE_OPERAND (op, 1))
146538fd1498Szrj * BITS_PER_UNIT;
146638fd1498Szrj op = TREE_OPERAND (op, 0);
146738fd1498Szrj }
146838fd1498Szrj else if (DECL_P (op))
146938fd1498Szrj ;
147038fd1498Szrj else
147138fd1498Szrj {
147238fd1498Szrj tci->speculative++;
147338fd1498Szrj return csftc_abort_walking_p (tci->speculative);
147438fd1498Szrj }
147538fd1498Szrj op = walk_ssa_copies (op);
147638fd1498Szrj }
147738fd1498Szrj if (operand_equal_p (op, tci->instance, 0)
147838fd1498Szrj && TYPE_SIZE (type)
147938fd1498Szrj && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
148038fd1498Szrj && tree_fits_shwi_p (TYPE_SIZE (type))
148138fd1498Szrj && tree_to_shwi (TYPE_SIZE (type)) + offset > tci->offset
148238fd1498Szrj /* Some inlined constructors may look as follows:
148338fd1498Szrj _3 = operator new (16);
148438fd1498Szrj MEM[(struct &)_3] ={v} {CLOBBER};
148538fd1498Szrj MEM[(struct CompositeClass *)_3]._vptr.CompositeClass
148638fd1498Szrj = &MEM[(void *)&_ZTV14CompositeClass + 16B];
148738fd1498Szrj _7 = &MEM[(struct CompositeClass *)_3].object;
148838fd1498Szrj EmptyClass::EmptyClass (_7);
148938fd1498Szrj
149038fd1498Szrj When determining dynamic type of _3 and because we stop at first
149138fd1498Szrj dynamic type found, we would stop on EmptyClass::EmptyClass (_7).
149238fd1498Szrj In this case the emptyclass is not even polymorphic and we miss
149338fd1498Szrj it is contained in an outer type that is polymorphic. */
149438fd1498Szrj
149538fd1498Szrj && (tci->offset == offset || contains_polymorphic_type_p (type)))
149638fd1498Szrj {
149738fd1498Szrj record_known_type (tci, type, tci->offset - offset);
149838fd1498Szrj return true;
149938fd1498Szrj }
150038fd1498Szrj }
150138fd1498Szrj /* Calls may possibly change dynamic type by placement new. Assume
150238fd1498Szrj it will not happen, but make result speculative only. */
150338fd1498Szrj if (dump_file)
150438fd1498Szrj {
150538fd1498Szrj fprintf (dump_file, " Function call may change dynamic type:");
150638fd1498Szrj print_gimple_stmt (dump_file, stmt, 0);
150738fd1498Szrj }
150838fd1498Szrj tci->speculative++;
150938fd1498Szrj return csftc_abort_walking_p (tci->speculative);
151038fd1498Szrj }
151138fd1498Szrj /* Check for inlined virtual table store. */
151238fd1498Szrj else if (noncall_stmt_may_be_vtbl_ptr_store (stmt))
151338fd1498Szrj {
151438fd1498Szrj tree type;
151538fd1498Szrj HOST_WIDE_INT offset = 0;
151638fd1498Szrj if (dump_file)
151738fd1498Szrj {
151838fd1498Szrj fprintf (dump_file, " Checking vtbl store: ");
151938fd1498Szrj print_gimple_stmt (dump_file, stmt, 0);
152038fd1498Szrj }
152138fd1498Szrj
152238fd1498Szrj type = extr_type_from_vtbl_ptr_store (stmt, tci, &offset);
152338fd1498Szrj if (type == error_mark_node)
152438fd1498Szrj return false;
152538fd1498Szrj gcc_assert (!type || TYPE_MAIN_VARIANT (type) == type);
152638fd1498Szrj if (!type)
152738fd1498Szrj {
152838fd1498Szrj if (dump_file)
152938fd1498Szrj fprintf (dump_file, " Unanalyzed store may change type.\n");
153038fd1498Szrj tci->seen_unanalyzed_store = true;
153138fd1498Szrj tci->speculative++;
153238fd1498Szrj }
153338fd1498Szrj else
153438fd1498Szrj record_known_type (tci, type, offset);
153538fd1498Szrj return true;
153638fd1498Szrj }
153738fd1498Szrj else
153838fd1498Szrj return false;
153938fd1498Szrj }
154038fd1498Szrj
154138fd1498Szrj /* THIS is polymorphic call context obtained from get_polymorphic_context.
154238fd1498Szrj OTR_OBJECT is pointer to the instance returned by OBJ_TYPE_REF_OBJECT.
154338fd1498Szrj INSTANCE is pointer to the outer instance as returned by
154438fd1498Szrj get_polymorphic_context. To avoid creation of temporary expressions,
154538fd1498Szrj INSTANCE may also be an declaration of get_polymorphic_context found the
154638fd1498Szrj value to be in static storage.
154738fd1498Szrj
154838fd1498Szrj If the type of instance is not fully determined
154938fd1498Szrj (either OUTER_TYPE is unknown or MAYBE_IN_CONSTRUCTION/INCLUDE_DERIVED_TYPES
155038fd1498Szrj is set), try to walk memory writes and find the actual construction of the
155138fd1498Szrj instance.
155238fd1498Szrj
155338fd1498Szrj Return true if memory is unchanged from function entry.
155438fd1498Szrj
155538fd1498Szrj We do not include this analysis in the context analysis itself, because
155638fd1498Szrj it needs memory SSA to be fully built and the walk may be expensive.
155738fd1498Szrj So it is not suitable for use withing fold_stmt and similar uses. */
155838fd1498Szrj
155938fd1498Szrj bool
get_dynamic_type(tree instance,tree otr_object,tree otr_type,gimple * call)156038fd1498Szrj ipa_polymorphic_call_context::get_dynamic_type (tree instance,
156138fd1498Szrj tree otr_object,
156238fd1498Szrj tree otr_type,
156338fd1498Szrj gimple *call)
156438fd1498Szrj {
156538fd1498Szrj struct type_change_info tci;
156638fd1498Szrj ao_ref ao;
156738fd1498Szrj bool function_entry_reached = false;
156838fd1498Szrj tree instance_ref = NULL;
156938fd1498Szrj gimple *stmt = call;
157038fd1498Szrj /* Remember OFFSET before it is modified by restrict_to_inner_class.
157138fd1498Szrj This is because we do not update INSTANCE when walking inwards. */
157238fd1498Szrj HOST_WIDE_INT instance_offset = offset;
157338fd1498Szrj tree instance_outer_type = outer_type;
157438fd1498Szrj
1575*58e805e6Szrj if (!instance)
1576*58e805e6Szrj return false;
1577*58e805e6Szrj
157838fd1498Szrj if (otr_type)
157938fd1498Szrj otr_type = TYPE_MAIN_VARIANT (otr_type);
158038fd1498Szrj
158138fd1498Szrj /* Walk into inner type. This may clear maybe_derived_type and save us
158238fd1498Szrj from useless work. It also makes later comparsions with static type
158338fd1498Szrj easier. */
158438fd1498Szrj if (outer_type && otr_type)
158538fd1498Szrj {
158638fd1498Szrj if (!restrict_to_inner_class (otr_type))
158738fd1498Szrj return false;
158838fd1498Szrj }
158938fd1498Szrj
159038fd1498Szrj if (!maybe_in_construction && !maybe_derived_type)
159138fd1498Szrj return false;
159238fd1498Szrj
159338fd1498Szrj /* If we are in fact not looking at any object object or the instance is
159438fd1498Szrj some placement new into a random load, give up straight away. */
159538fd1498Szrj if (TREE_CODE (instance) == MEM_REF)
159638fd1498Szrj return false;
159738fd1498Szrj
159838fd1498Szrj /* We need to obtain refernce to virtual table pointer. It is better
159938fd1498Szrj to look it up in the code rather than build our own. This require bit
160038fd1498Szrj of pattern matching, but we end up verifying that what we found is
160138fd1498Szrj correct.
160238fd1498Szrj
160338fd1498Szrj What we pattern match is:
160438fd1498Szrj
160538fd1498Szrj tmp = instance->_vptr.A; // vtbl ptr load
160638fd1498Szrj tmp2 = tmp[otr_token]; // vtable lookup
160738fd1498Szrj OBJ_TYPE_REF(tmp2;instance->0) (instance);
160838fd1498Szrj
160938fd1498Szrj We want to start alias oracle walk from vtbl pointer load,
161038fd1498Szrj but we may not be able to identify it, for example, when PRE moved the
161138fd1498Szrj load around. */
161238fd1498Szrj
161338fd1498Szrj if (gimple_code (call) == GIMPLE_CALL)
161438fd1498Szrj {
161538fd1498Szrj tree ref = gimple_call_fn (call);
161638fd1498Szrj bool reverse;
161738fd1498Szrj
161838fd1498Szrj if (TREE_CODE (ref) == OBJ_TYPE_REF)
161938fd1498Szrj {
162038fd1498Szrj ref = OBJ_TYPE_REF_EXPR (ref);
162138fd1498Szrj ref = walk_ssa_copies (ref);
162238fd1498Szrj
162338fd1498Szrj /* If call target is already known, no need to do the expensive
162438fd1498Szrj memory walk. */
162538fd1498Szrj if (is_gimple_min_invariant (ref))
162638fd1498Szrj return false;
162738fd1498Szrj
162838fd1498Szrj /* Check if definition looks like vtable lookup. */
162938fd1498Szrj if (TREE_CODE (ref) == SSA_NAME
163038fd1498Szrj && !SSA_NAME_IS_DEFAULT_DEF (ref)
163138fd1498Szrj && gimple_assign_load_p (SSA_NAME_DEF_STMT (ref))
163238fd1498Szrj && TREE_CODE (gimple_assign_rhs1
163338fd1498Szrj (SSA_NAME_DEF_STMT (ref))) == MEM_REF)
163438fd1498Szrj {
163538fd1498Szrj ref = get_base_address
163638fd1498Szrj (TREE_OPERAND (gimple_assign_rhs1
163738fd1498Szrj (SSA_NAME_DEF_STMT (ref)), 0));
163838fd1498Szrj ref = walk_ssa_copies (ref);
163938fd1498Szrj /* Find base address of the lookup and see if it looks like
164038fd1498Szrj vptr load. */
164138fd1498Szrj if (TREE_CODE (ref) == SSA_NAME
164238fd1498Szrj && !SSA_NAME_IS_DEFAULT_DEF (ref)
164338fd1498Szrj && gimple_assign_load_p (SSA_NAME_DEF_STMT (ref)))
164438fd1498Szrj {
164538fd1498Szrj HOST_WIDE_INT offset2, size;
164638fd1498Szrj tree ref_exp = gimple_assign_rhs1 (SSA_NAME_DEF_STMT (ref));
164738fd1498Szrj tree base_ref
164838fd1498Szrj = get_ref_base_and_extent_hwi (ref_exp, &offset2,
164938fd1498Szrj &size, &reverse);
165038fd1498Szrj
165138fd1498Szrj /* Finally verify that what we found looks like read from
165238fd1498Szrj OTR_OBJECT or from INSTANCE with offset OFFSET. */
165338fd1498Szrj if (base_ref
165438fd1498Szrj && ((TREE_CODE (base_ref) == MEM_REF
165538fd1498Szrj && ((offset2 == instance_offset
165638fd1498Szrj && TREE_OPERAND (base_ref, 0) == instance)
165738fd1498Szrj || (!offset2
165838fd1498Szrj && TREE_OPERAND (base_ref, 0)
165938fd1498Szrj == otr_object)))
166038fd1498Szrj || (DECL_P (instance) && base_ref == instance
166138fd1498Szrj && offset2 == instance_offset)))
166238fd1498Szrj {
166338fd1498Szrj stmt = SSA_NAME_DEF_STMT (ref);
166438fd1498Szrj instance_ref = ref_exp;
166538fd1498Szrj }
166638fd1498Szrj }
166738fd1498Szrj }
166838fd1498Szrj }
166938fd1498Szrj }
167038fd1498Szrj
167138fd1498Szrj /* If we failed to look up the reference in code, build our own. */
167238fd1498Szrj if (!instance_ref)
167338fd1498Szrj {
167438fd1498Szrj /* If the statement in question does not use memory, we can't tell
167538fd1498Szrj anything. */
167638fd1498Szrj if (!gimple_vuse (stmt))
167738fd1498Szrj return false;
167838fd1498Szrj ao_ref_init_from_ptr_and_size (&ao, otr_object, NULL);
167938fd1498Szrj }
168038fd1498Szrj else
168138fd1498Szrj /* Otherwise use the real reference. */
168238fd1498Szrj ao_ref_init (&ao, instance_ref);
168338fd1498Szrj
168438fd1498Szrj /* We look for vtbl pointer read. */
168538fd1498Szrj ao.size = POINTER_SIZE;
168638fd1498Szrj ao.max_size = ao.size;
168738fd1498Szrj /* We are looking for stores to vptr pointer within the instance of
168838fd1498Szrj outer type.
168938fd1498Szrj TODO: The vptr pointer type is globally known, we probably should
169038fd1498Szrj keep it and do that even when otr_type is unknown. */
169138fd1498Szrj if (otr_type)
169238fd1498Szrj {
169338fd1498Szrj ao.base_alias_set
169438fd1498Szrj = get_alias_set (outer_type ? outer_type : otr_type);
169538fd1498Szrj ao.ref_alias_set
169638fd1498Szrj = get_alias_set (TREE_TYPE (BINFO_VTABLE (TYPE_BINFO (otr_type))));
169738fd1498Szrj }
169838fd1498Szrj
169938fd1498Szrj if (dump_file)
170038fd1498Szrj {
170138fd1498Szrj fprintf (dump_file, "Determining dynamic type for call: ");
170238fd1498Szrj print_gimple_stmt (dump_file, call, 0);
170338fd1498Szrj fprintf (dump_file, " Starting walk at: ");
170438fd1498Szrj print_gimple_stmt (dump_file, stmt, 0);
170538fd1498Szrj fprintf (dump_file, " instance pointer: ");
170638fd1498Szrj print_generic_expr (dump_file, otr_object, TDF_SLIM);
170738fd1498Szrj fprintf (dump_file, " Outer instance pointer: ");
170838fd1498Szrj print_generic_expr (dump_file, instance, TDF_SLIM);
170938fd1498Szrj fprintf (dump_file, " offset: %i (bits)", (int)instance_offset);
171038fd1498Szrj fprintf (dump_file, " vtbl reference: ");
171138fd1498Szrj print_generic_expr (dump_file, instance_ref, TDF_SLIM);
171238fd1498Szrj fprintf (dump_file, "\n");
171338fd1498Szrj }
171438fd1498Szrj
171538fd1498Szrj tci.offset = instance_offset;
171638fd1498Szrj tci.instance = instance;
171738fd1498Szrj tci.vtbl_ptr_ref = instance_ref;
171838fd1498Szrj tci.known_current_type = NULL_TREE;
171938fd1498Szrj tci.known_current_offset = 0;
172038fd1498Szrj tci.otr_type = otr_type;
172138fd1498Szrj tci.type_maybe_changed = false;
172238fd1498Szrj tci.multiple_types_encountered = false;
172338fd1498Szrj tci.speculative = 0;
172438fd1498Szrj tci.seen_unanalyzed_store = false;
172538fd1498Szrj
172638fd1498Szrj walk_aliased_vdefs (&ao, gimple_vuse (stmt), check_stmt_for_type_change,
172738fd1498Szrj &tci, NULL, &function_entry_reached);
172838fd1498Szrj
172938fd1498Szrj /* If we did not find any type changing statements, we may still drop
173038fd1498Szrj maybe_in_construction flag if the context already have outer type.
173138fd1498Szrj
173238fd1498Szrj Here we make special assumptions about both constructors and
173338fd1498Szrj destructors which are all the functions that are allowed to alter the
173438fd1498Szrj VMT pointers. It assumes that destructors begin with assignment into
173538fd1498Szrj all VMT pointers and that constructors essentially look in the
173638fd1498Szrj following way:
173738fd1498Szrj
173838fd1498Szrj 1) The very first thing they do is that they call constructors of
173938fd1498Szrj ancestor sub-objects that have them.
174038fd1498Szrj
174138fd1498Szrj 2) Then VMT pointers of this and all its ancestors is set to new
174238fd1498Szrj values corresponding to the type corresponding to the constructor.
174338fd1498Szrj
174438fd1498Szrj 3) Only afterwards, other stuff such as constructor of member
174538fd1498Szrj sub-objects and the code written by the user is run. Only this may
174638fd1498Szrj include calling virtual functions, directly or indirectly.
174738fd1498Szrj
174838fd1498Szrj 4) placement new can not be used to change type of non-POD statically
174938fd1498Szrj allocated variables.
175038fd1498Szrj
175138fd1498Szrj There is no way to call a constructor of an ancestor sub-object in any
175238fd1498Szrj other way.
175338fd1498Szrj
175438fd1498Szrj This means that we do not have to care whether constructors get the
175538fd1498Szrj correct type information because they will always change it (in fact,
175638fd1498Szrj if we define the type to be given by the VMT pointer, it is undefined).
175738fd1498Szrj
175838fd1498Szrj The most important fact to derive from the above is that if, for some
175938fd1498Szrj statement in the section 3, we try to detect whether the dynamic type
176038fd1498Szrj has changed, we can safely ignore all calls as we examine the function
176138fd1498Szrj body backwards until we reach statements in section 2 because these
176238fd1498Szrj calls cannot be ancestor constructors or destructors (if the input is
176338fd1498Szrj not bogus) and so do not change the dynamic type (this holds true only
176438fd1498Szrj for automatically allocated objects but at the moment we devirtualize
176538fd1498Szrj only these). We then must detect that statements in section 2 change
176638fd1498Szrj the dynamic type and can try to derive the new type. That is enough
176738fd1498Szrj and we can stop, we will never see the calls into constructors of
176838fd1498Szrj sub-objects in this code.
176938fd1498Szrj
177038fd1498Szrj Therefore if the static outer type was found (outer_type)
177138fd1498Szrj we can safely ignore tci.speculative that is set on calls and give up
177238fd1498Szrj only if there was dyanmic type store that may affect given variable
177338fd1498Szrj (seen_unanalyzed_store) */
177438fd1498Szrj
177538fd1498Szrj if (!tci.type_maybe_changed
177638fd1498Szrj || (outer_type
177738fd1498Szrj && !dynamic
177838fd1498Szrj && !tci.seen_unanalyzed_store
177938fd1498Szrj && !tci.multiple_types_encountered
178038fd1498Szrj && ((offset == tci.offset
178138fd1498Szrj && types_same_for_odr (tci.known_current_type,
178238fd1498Szrj outer_type))
178338fd1498Szrj || (instance_offset == offset
178438fd1498Szrj && types_same_for_odr (tci.known_current_type,
178538fd1498Szrj instance_outer_type)))))
178638fd1498Szrj {
178738fd1498Szrj if (!outer_type || tci.seen_unanalyzed_store)
178838fd1498Szrj return false;
178938fd1498Szrj if (maybe_in_construction)
179038fd1498Szrj maybe_in_construction = false;
179138fd1498Szrj if (dump_file)
179238fd1498Szrj fprintf (dump_file, " No dynamic type change found.\n");
179338fd1498Szrj return true;
179438fd1498Szrj }
179538fd1498Szrj
179638fd1498Szrj if (tci.known_current_type
179738fd1498Szrj && !function_entry_reached
179838fd1498Szrj && !tci.multiple_types_encountered)
179938fd1498Szrj {
180038fd1498Szrj if (!tci.speculative)
180138fd1498Szrj {
180238fd1498Szrj outer_type = TYPE_MAIN_VARIANT (tci.known_current_type);
180338fd1498Szrj offset = tci.known_current_offset;
180438fd1498Szrj dynamic = true;
180538fd1498Szrj maybe_in_construction = false;
180638fd1498Szrj maybe_derived_type = false;
180738fd1498Szrj if (dump_file)
180838fd1498Szrj fprintf (dump_file, " Determined dynamic type.\n");
180938fd1498Szrj }
181038fd1498Szrj else if (!speculative_outer_type
181138fd1498Szrj || speculative_maybe_derived_type)
181238fd1498Szrj {
181338fd1498Szrj speculative_outer_type = TYPE_MAIN_VARIANT (tci.known_current_type);
181438fd1498Szrj speculative_offset = tci.known_current_offset;
181538fd1498Szrj speculative_maybe_derived_type = false;
181638fd1498Szrj if (dump_file)
181738fd1498Szrj fprintf (dump_file, " Determined speculative dynamic type.\n");
181838fd1498Szrj }
181938fd1498Szrj }
182038fd1498Szrj else if (dump_file)
182138fd1498Szrj {
182238fd1498Szrj fprintf (dump_file, " Found multiple types%s%s\n",
182338fd1498Szrj function_entry_reached ? " (function entry reached)" : "",
182438fd1498Szrj function_entry_reached ? " (multiple types encountered)" : "");
182538fd1498Szrj }
182638fd1498Szrj
182738fd1498Szrj return false;
182838fd1498Szrj }
182938fd1498Szrj
183038fd1498Szrj /* See if speculation given by SPEC_OUTER_TYPE, SPEC_OFFSET and SPEC_MAYBE_DERIVED_TYPE
183138fd1498Szrj seems consistent (and useful) with what we already have in the non-speculative context. */
183238fd1498Szrj
183338fd1498Szrj bool
speculation_consistent_p(tree spec_outer_type,HOST_WIDE_INT spec_offset,bool spec_maybe_derived_type,tree otr_type)183438fd1498Szrj ipa_polymorphic_call_context::speculation_consistent_p (tree spec_outer_type,
183538fd1498Szrj HOST_WIDE_INT spec_offset,
183638fd1498Szrj bool spec_maybe_derived_type,
183738fd1498Szrj tree otr_type) const
183838fd1498Szrj {
183938fd1498Szrj if (!flag_devirtualize_speculatively)
184038fd1498Szrj return false;
184138fd1498Szrj
184238fd1498Szrj /* Non-polymorphic types are useless for deriving likely polymorphic
184338fd1498Szrj call targets. */
184438fd1498Szrj if (!spec_outer_type || !contains_polymorphic_type_p (spec_outer_type))
184538fd1498Szrj return false;
184638fd1498Szrj
184738fd1498Szrj /* If we know nothing, speculation is always good. */
184838fd1498Szrj if (!outer_type)
184938fd1498Szrj return true;
185038fd1498Szrj
185138fd1498Szrj /* Speculation is only useful to avoid derived types.
185238fd1498Szrj This is not 100% true for placement new, where the outer context may
185338fd1498Szrj turn out to be useless, but ignore these for now. */
185438fd1498Szrj if (!maybe_derived_type)
185538fd1498Szrj return false;
185638fd1498Szrj
185738fd1498Szrj /* If types agrees, speculation is consistent, but it makes sense only
185838fd1498Szrj when it says something new. */
185938fd1498Szrj if (types_must_be_same_for_odr (spec_outer_type, outer_type))
186038fd1498Szrj return maybe_derived_type && !spec_maybe_derived_type;
186138fd1498Szrj
186238fd1498Szrj /* If speculation does not contain the type in question, ignore it. */
186338fd1498Szrj if (otr_type
186438fd1498Szrj && !contains_type_p (spec_outer_type, spec_offset, otr_type, false, true))
186538fd1498Szrj return false;
186638fd1498Szrj
186738fd1498Szrj /* If outer type already contains speculation as a filed,
186838fd1498Szrj it is useless. We already know from OUTER_TYPE
186938fd1498Szrj SPEC_TYPE and that it is not in the construction. */
187038fd1498Szrj if (contains_type_p (outer_type, offset - spec_offset,
187138fd1498Szrj spec_outer_type, false, false))
187238fd1498Szrj return false;
187338fd1498Szrj
187438fd1498Szrj /* If speculative outer type is not more specified than outer
187538fd1498Szrj type, just give up.
187638fd1498Szrj We can only decide this safely if we can compare types with OUTER_TYPE.
187738fd1498Szrj */
187838fd1498Szrj if ((!in_lto_p || odr_type_p (outer_type))
187938fd1498Szrj && !contains_type_p (spec_outer_type,
188038fd1498Szrj spec_offset - offset,
188138fd1498Szrj outer_type, false))
188238fd1498Szrj return false;
188338fd1498Szrj return true;
188438fd1498Szrj }
188538fd1498Szrj
188638fd1498Szrj /* Improve THIS with speculation described by NEW_OUTER_TYPE, NEW_OFFSET,
188738fd1498Szrj NEW_MAYBE_DERIVED_TYPE
188838fd1498Szrj If OTR_TYPE is set, assume the context is used with OTR_TYPE. */
188938fd1498Szrj
189038fd1498Szrj bool
combine_speculation_with(tree new_outer_type,HOST_WIDE_INT new_offset,bool new_maybe_derived_type,tree otr_type)189138fd1498Szrj ipa_polymorphic_call_context::combine_speculation_with
189238fd1498Szrj (tree new_outer_type, HOST_WIDE_INT new_offset, bool new_maybe_derived_type,
189338fd1498Szrj tree otr_type)
189438fd1498Szrj {
189538fd1498Szrj if (!new_outer_type)
189638fd1498Szrj return false;
189738fd1498Szrj
189838fd1498Szrj /* restrict_to_inner_class may eliminate wrong speculation making our job
189938fd1498Szrj easeier. */
190038fd1498Szrj if (otr_type)
190138fd1498Szrj restrict_to_inner_class (otr_type);
190238fd1498Szrj
190338fd1498Szrj if (!speculation_consistent_p (new_outer_type, new_offset,
190438fd1498Szrj new_maybe_derived_type, otr_type))
190538fd1498Szrj return false;
190638fd1498Szrj
190738fd1498Szrj /* New speculation is a win in case we have no speculation or new
190838fd1498Szrj speculation does not consider derivations. */
190938fd1498Szrj if (!speculative_outer_type
191038fd1498Szrj || (speculative_maybe_derived_type
191138fd1498Szrj && !new_maybe_derived_type))
191238fd1498Szrj {
191338fd1498Szrj speculative_outer_type = new_outer_type;
191438fd1498Szrj speculative_offset = new_offset;
191538fd1498Szrj speculative_maybe_derived_type = new_maybe_derived_type;
191638fd1498Szrj return true;
191738fd1498Szrj }
191838fd1498Szrj else if (types_must_be_same_for_odr (speculative_outer_type,
191938fd1498Szrj new_outer_type))
192038fd1498Szrj {
192138fd1498Szrj if (speculative_offset != new_offset)
192238fd1498Szrj {
192338fd1498Szrj /* OK we have two contexts that seems valid but they disagree,
192438fd1498Szrj just give up.
192538fd1498Szrj
192638fd1498Szrj This is not a lattice operation, so we may want to drop it later. */
192738fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
192838fd1498Szrj fprintf (dump_file,
192938fd1498Szrj "Speculative outer types match, "
193038fd1498Szrj "offset mismatch -> invalid speculation\n");
193138fd1498Szrj clear_speculation ();
193238fd1498Szrj return true;
193338fd1498Szrj }
193438fd1498Szrj else
193538fd1498Szrj {
193638fd1498Szrj if (speculative_maybe_derived_type && !new_maybe_derived_type)
193738fd1498Szrj {
193838fd1498Szrj speculative_maybe_derived_type = false;
193938fd1498Szrj return true;
194038fd1498Szrj }
194138fd1498Szrj else
194238fd1498Szrj return false;
194338fd1498Szrj }
194438fd1498Szrj }
194538fd1498Szrj /* Choose type that contains the other. This one either contains the outer
194638fd1498Szrj as a field (thus giving exactly one target) or is deeper in the type
194738fd1498Szrj hiearchy. */
194838fd1498Szrj else if (speculative_outer_type
194938fd1498Szrj && speculative_maybe_derived_type
195038fd1498Szrj && (new_offset > speculative_offset
195138fd1498Szrj || (new_offset == speculative_offset
195238fd1498Szrj && contains_type_p (new_outer_type,
195338fd1498Szrj 0, speculative_outer_type, false))))
195438fd1498Szrj {
195538fd1498Szrj tree old_outer_type = speculative_outer_type;
195638fd1498Szrj HOST_WIDE_INT old_offset = speculative_offset;
195738fd1498Szrj bool old_maybe_derived_type = speculative_maybe_derived_type;
195838fd1498Szrj
195938fd1498Szrj speculative_outer_type = new_outer_type;
196038fd1498Szrj speculative_offset = new_offset;
196138fd1498Szrj speculative_maybe_derived_type = new_maybe_derived_type;
196238fd1498Szrj
196338fd1498Szrj if (otr_type)
196438fd1498Szrj restrict_to_inner_class (otr_type);
196538fd1498Szrj
196638fd1498Szrj /* If the speculation turned out to make no sense, revert to sensible
196738fd1498Szrj one. */
196838fd1498Szrj if (!speculative_outer_type)
196938fd1498Szrj {
197038fd1498Szrj speculative_outer_type = old_outer_type;
197138fd1498Szrj speculative_offset = old_offset;
197238fd1498Szrj speculative_maybe_derived_type = old_maybe_derived_type;
197338fd1498Szrj return false;
197438fd1498Szrj }
197538fd1498Szrj return (old_offset != speculative_offset
197638fd1498Szrj || old_maybe_derived_type != speculative_maybe_derived_type
197738fd1498Szrj || types_must_be_same_for_odr (speculative_outer_type,
197838fd1498Szrj new_outer_type));
197938fd1498Szrj }
198038fd1498Szrj return false;
198138fd1498Szrj }
198238fd1498Szrj
198338fd1498Szrj /* Make speculation less specific so
198438fd1498Szrj NEW_OUTER_TYPE, NEW_OFFSET, NEW_MAYBE_DERIVED_TYPE is also included.
198538fd1498Szrj If OTR_TYPE is set, assume the context is used with OTR_TYPE. */
198638fd1498Szrj
198738fd1498Szrj bool
meet_speculation_with(tree new_outer_type,HOST_WIDE_INT new_offset,bool new_maybe_derived_type,tree otr_type)198838fd1498Szrj ipa_polymorphic_call_context::meet_speculation_with
198938fd1498Szrj (tree new_outer_type, HOST_WIDE_INT new_offset, bool new_maybe_derived_type,
199038fd1498Szrj tree otr_type)
199138fd1498Szrj {
199238fd1498Szrj if (!new_outer_type && speculative_outer_type)
199338fd1498Szrj {
199438fd1498Szrj clear_speculation ();
199538fd1498Szrj return true;
199638fd1498Szrj }
199738fd1498Szrj
199838fd1498Szrj /* restrict_to_inner_class may eliminate wrong speculation making our job
199938fd1498Szrj easeier. */
200038fd1498Szrj if (otr_type)
200138fd1498Szrj restrict_to_inner_class (otr_type);
200238fd1498Szrj
200338fd1498Szrj if (!speculative_outer_type
200438fd1498Szrj || !speculation_consistent_p (speculative_outer_type,
200538fd1498Szrj speculative_offset,
200638fd1498Szrj speculative_maybe_derived_type,
200738fd1498Szrj otr_type))
200838fd1498Szrj return false;
200938fd1498Szrj
201038fd1498Szrj if (!speculation_consistent_p (new_outer_type, new_offset,
201138fd1498Szrj new_maybe_derived_type, otr_type))
201238fd1498Szrj {
201338fd1498Szrj clear_speculation ();
201438fd1498Szrj return true;
201538fd1498Szrj }
201638fd1498Szrj
201738fd1498Szrj else if (types_must_be_same_for_odr (speculative_outer_type,
201838fd1498Szrj new_outer_type))
201938fd1498Szrj {
202038fd1498Szrj if (speculative_offset != new_offset)
202138fd1498Szrj {
202238fd1498Szrj clear_speculation ();
202338fd1498Szrj return true;
202438fd1498Szrj }
202538fd1498Szrj else
202638fd1498Szrj {
202738fd1498Szrj if (!speculative_maybe_derived_type && new_maybe_derived_type)
202838fd1498Szrj {
202938fd1498Szrj speculative_maybe_derived_type = true;
203038fd1498Szrj return true;
203138fd1498Szrj }
203238fd1498Szrj else
203338fd1498Szrj return false;
203438fd1498Szrj }
203538fd1498Szrj }
203638fd1498Szrj /* See if one type contains the other as a field (not base). */
203738fd1498Szrj else if (contains_type_p (new_outer_type, new_offset - speculative_offset,
203838fd1498Szrj speculative_outer_type, false, false))
203938fd1498Szrj return false;
204038fd1498Szrj else if (contains_type_p (speculative_outer_type,
204138fd1498Szrj speculative_offset - new_offset,
204238fd1498Szrj new_outer_type, false, false))
204338fd1498Szrj {
204438fd1498Szrj speculative_outer_type = new_outer_type;
204538fd1498Szrj speculative_offset = new_offset;
204638fd1498Szrj speculative_maybe_derived_type = new_maybe_derived_type;
204738fd1498Szrj return true;
204838fd1498Szrj }
204938fd1498Szrj /* See if OUTER_TYPE is base of CTX.OUTER_TYPE. */
205038fd1498Szrj else if (contains_type_p (new_outer_type,
205138fd1498Szrj new_offset - speculative_offset,
205238fd1498Szrj speculative_outer_type, false, true))
205338fd1498Szrj {
205438fd1498Szrj if (!speculative_maybe_derived_type)
205538fd1498Szrj {
205638fd1498Szrj speculative_maybe_derived_type = true;
205738fd1498Szrj return true;
205838fd1498Szrj }
205938fd1498Szrj return false;
206038fd1498Szrj }
206138fd1498Szrj /* See if CTX.OUTER_TYPE is base of OUTER_TYPE. */
206238fd1498Szrj else if (contains_type_p (speculative_outer_type,
206338fd1498Szrj speculative_offset - new_offset, new_outer_type, false, true))
206438fd1498Szrj {
206538fd1498Szrj speculative_outer_type = new_outer_type;
206638fd1498Szrj speculative_offset = new_offset;
206738fd1498Szrj speculative_maybe_derived_type = true;
206838fd1498Szrj return true;
206938fd1498Szrj }
207038fd1498Szrj else
207138fd1498Szrj {
207238fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
207338fd1498Szrj fprintf (dump_file, "Giving up on speculative meet\n");
207438fd1498Szrj clear_speculation ();
207538fd1498Szrj return true;
207638fd1498Szrj }
207738fd1498Szrj }
207838fd1498Szrj
207938fd1498Szrj /* Assume that both THIS and a given context is valid and strenghten THIS
208038fd1498Szrj if possible. Return true if any strenghtening was made.
208138fd1498Szrj If actual type the context is being used in is known, OTR_TYPE should be
208238fd1498Szrj set accordingly. This improves quality of combined result. */
208338fd1498Szrj
208438fd1498Szrj bool
combine_with(ipa_polymorphic_call_context ctx,tree otr_type)208538fd1498Szrj ipa_polymorphic_call_context::combine_with (ipa_polymorphic_call_context ctx,
208638fd1498Szrj tree otr_type)
208738fd1498Szrj {
208838fd1498Szrj bool updated = false;
208938fd1498Szrj
209038fd1498Szrj if (ctx.useless_p () || invalid)
209138fd1498Szrj return false;
209238fd1498Szrj
209338fd1498Szrj /* Restricting context to inner type makes merging easier, however do not
209438fd1498Szrj do that unless we know how the context is used (OTR_TYPE is non-NULL) */
209538fd1498Szrj if (otr_type && !invalid && !ctx.invalid)
209638fd1498Szrj {
209738fd1498Szrj restrict_to_inner_class (otr_type);
209838fd1498Szrj ctx.restrict_to_inner_class (otr_type);
209938fd1498Szrj if(invalid)
210038fd1498Szrj return false;
210138fd1498Szrj }
210238fd1498Szrj
210338fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
210438fd1498Szrj {
210538fd1498Szrj fprintf (dump_file, "Polymorphic call context combine:");
210638fd1498Szrj dump (dump_file);
210738fd1498Szrj fprintf (dump_file, "With context: ");
210838fd1498Szrj ctx.dump (dump_file);
210938fd1498Szrj if (otr_type)
211038fd1498Szrj {
211138fd1498Szrj fprintf (dump_file, "To be used with type: ");
211238fd1498Szrj print_generic_expr (dump_file, otr_type, TDF_SLIM);
211338fd1498Szrj fprintf (dump_file, "\n");
211438fd1498Szrj }
211538fd1498Szrj }
211638fd1498Szrj
211738fd1498Szrj /* If call is known to be invalid, we are done. */
211838fd1498Szrj if (ctx.invalid)
211938fd1498Szrj {
212038fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
212138fd1498Szrj fprintf (dump_file, "-> Invalid context\n");
212238fd1498Szrj goto invalidate;
212338fd1498Szrj }
212438fd1498Szrj
212538fd1498Szrj if (!ctx.outer_type)
212638fd1498Szrj ;
212738fd1498Szrj else if (!outer_type)
212838fd1498Szrj {
212938fd1498Szrj outer_type = ctx.outer_type;
213038fd1498Szrj offset = ctx.offset;
213138fd1498Szrj dynamic = ctx.dynamic;
213238fd1498Szrj maybe_in_construction = ctx.maybe_in_construction;
213338fd1498Szrj maybe_derived_type = ctx.maybe_derived_type;
213438fd1498Szrj updated = true;
213538fd1498Szrj }
213638fd1498Szrj /* If types are known to be same, merging is quite easy. */
213738fd1498Szrj else if (types_must_be_same_for_odr (outer_type, ctx.outer_type))
213838fd1498Szrj {
213938fd1498Szrj if (offset != ctx.offset
214038fd1498Szrj && TYPE_SIZE (outer_type)
214138fd1498Szrj && TREE_CODE (TYPE_SIZE (outer_type)) == INTEGER_CST)
214238fd1498Szrj {
214338fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
214438fd1498Szrj fprintf (dump_file, "Outer types match, offset mismatch -> invalid\n");
214538fd1498Szrj clear_speculation ();
214638fd1498Szrj clear_outer_type ();
214738fd1498Szrj invalid = true;
214838fd1498Szrj return true;
214938fd1498Szrj }
215038fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
215138fd1498Szrj fprintf (dump_file, "Outer types match, merging flags\n");
215238fd1498Szrj if (maybe_in_construction && !ctx.maybe_in_construction)
215338fd1498Szrj {
215438fd1498Szrj updated = true;
215538fd1498Szrj maybe_in_construction = false;
215638fd1498Szrj }
215738fd1498Szrj if (maybe_derived_type && !ctx.maybe_derived_type)
215838fd1498Szrj {
215938fd1498Szrj updated = true;
216038fd1498Szrj maybe_derived_type = false;
216138fd1498Szrj }
216238fd1498Szrj if (dynamic && !ctx.dynamic)
216338fd1498Szrj {
216438fd1498Szrj updated = true;
216538fd1498Szrj dynamic = false;
216638fd1498Szrj }
216738fd1498Szrj }
216838fd1498Szrj /* If we know the type precisely, there is not much to improve. */
216938fd1498Szrj else if (!maybe_derived_type && !maybe_in_construction
217038fd1498Szrj && !ctx.maybe_derived_type && !ctx.maybe_in_construction)
217138fd1498Szrj {
217238fd1498Szrj /* It may be easy to check if second context permits the first
217338fd1498Szrj and set INVALID otherwise. This is not easy to do in general;
217438fd1498Szrj contains_type_p may return false negatives for non-comparable
217538fd1498Szrj types.
217638fd1498Szrj
217738fd1498Szrj If OTR_TYPE is known, we however can expect that
217838fd1498Szrj restrict_to_inner_class should have discovered the same base
217938fd1498Szrj type. */
218038fd1498Szrj if (otr_type && !ctx.maybe_in_construction && !ctx.maybe_derived_type)
218138fd1498Szrj {
218238fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
218338fd1498Szrj fprintf (dump_file, "Contextes disagree -> invalid\n");
218438fd1498Szrj goto invalidate;
218538fd1498Szrj }
218638fd1498Szrj }
218738fd1498Szrj /* See if one type contains the other as a field (not base).
218838fd1498Szrj In this case we want to choose the wider type, because it contains
218938fd1498Szrj more information. */
219038fd1498Szrj else if (contains_type_p (ctx.outer_type, ctx.offset - offset,
219138fd1498Szrj outer_type, false, false))
219238fd1498Szrj {
219338fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
219438fd1498Szrj fprintf (dump_file, "Second type contain the first as a field\n");
219538fd1498Szrj
219638fd1498Szrj if (maybe_derived_type)
219738fd1498Szrj {
219838fd1498Szrj outer_type = ctx.outer_type;
219938fd1498Szrj maybe_derived_type = ctx.maybe_derived_type;
220038fd1498Szrj offset = ctx.offset;
220138fd1498Szrj dynamic = ctx.dynamic;
220238fd1498Szrj updated = true;
220338fd1498Szrj }
220438fd1498Szrj
220538fd1498Szrj /* If we do not know how the context is being used, we can
220638fd1498Szrj not clear MAYBE_IN_CONSTRUCTION because it may be offseted
220738fd1498Szrj to other component of OUTER_TYPE later and we know nothing
220838fd1498Szrj about it. */
220938fd1498Szrj if (otr_type && maybe_in_construction
221038fd1498Szrj && !ctx.maybe_in_construction)
221138fd1498Szrj {
221238fd1498Szrj maybe_in_construction = false;
221338fd1498Szrj updated = true;
221438fd1498Szrj }
221538fd1498Szrj }
221638fd1498Szrj else if (contains_type_p (outer_type, offset - ctx.offset,
221738fd1498Szrj ctx.outer_type, false, false))
221838fd1498Szrj {
221938fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
222038fd1498Szrj fprintf (dump_file, "First type contain the second as a field\n");
222138fd1498Szrj
222238fd1498Szrj if (otr_type && maybe_in_construction
222338fd1498Szrj && !ctx.maybe_in_construction)
222438fd1498Szrj {
222538fd1498Szrj maybe_in_construction = false;
222638fd1498Szrj updated = true;
222738fd1498Szrj }
222838fd1498Szrj }
222938fd1498Szrj /* See if OUTER_TYPE is base of CTX.OUTER_TYPE. */
223038fd1498Szrj else if (contains_type_p (ctx.outer_type,
223138fd1498Szrj ctx.offset - offset, outer_type, false, true))
223238fd1498Szrj {
223338fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
223438fd1498Szrj fprintf (dump_file, "First type is base of second\n");
223538fd1498Szrj if (!maybe_derived_type)
223638fd1498Szrj {
223738fd1498Szrj if (!ctx.maybe_in_construction
223838fd1498Szrj && types_odr_comparable (outer_type, ctx.outer_type))
223938fd1498Szrj {
224038fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
224138fd1498Szrj fprintf (dump_file, "Second context does not permit base -> invalid\n");
224238fd1498Szrj goto invalidate;
224338fd1498Szrj }
224438fd1498Szrj }
224538fd1498Szrj /* Pick variant deeper in the hiearchy. */
224638fd1498Szrj else
224738fd1498Szrj {
224838fd1498Szrj outer_type = ctx.outer_type;
224938fd1498Szrj maybe_in_construction = ctx.maybe_in_construction;
225038fd1498Szrj maybe_derived_type = ctx.maybe_derived_type;
225138fd1498Szrj offset = ctx.offset;
225238fd1498Szrj dynamic = ctx.dynamic;
225338fd1498Szrj updated = true;
225438fd1498Szrj }
225538fd1498Szrj }
225638fd1498Szrj /* See if CTX.OUTER_TYPE is base of OUTER_TYPE. */
225738fd1498Szrj else if (contains_type_p (outer_type,
225838fd1498Szrj offset - ctx.offset, ctx.outer_type, false, true))
225938fd1498Szrj {
226038fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
226138fd1498Szrj fprintf (dump_file, "Second type is base of first\n");
226238fd1498Szrj if (!ctx.maybe_derived_type)
226338fd1498Szrj {
226438fd1498Szrj if (!maybe_in_construction
226538fd1498Szrj && types_odr_comparable (outer_type, ctx.outer_type))
226638fd1498Szrj {
226738fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
226838fd1498Szrj fprintf (dump_file, "First context does not permit base -> invalid\n");
226938fd1498Szrj goto invalidate;
227038fd1498Szrj }
227138fd1498Szrj /* Pick the base type. */
227238fd1498Szrj else if (maybe_in_construction)
227338fd1498Szrj {
227438fd1498Szrj outer_type = ctx.outer_type;
227538fd1498Szrj maybe_in_construction = ctx.maybe_in_construction;
227638fd1498Szrj maybe_derived_type = ctx.maybe_derived_type;
227738fd1498Szrj offset = ctx.offset;
227838fd1498Szrj dynamic = ctx.dynamic;
227938fd1498Szrj updated = true;
228038fd1498Szrj }
228138fd1498Szrj }
228238fd1498Szrj }
228338fd1498Szrj /* TODO handle merging using hiearchy. */
228438fd1498Szrj else if (dump_file && (dump_flags & TDF_DETAILS))
228538fd1498Szrj fprintf (dump_file, "Giving up on merge\n");
228638fd1498Szrj
228738fd1498Szrj updated |= combine_speculation_with (ctx.speculative_outer_type,
228838fd1498Szrj ctx.speculative_offset,
228938fd1498Szrj ctx.speculative_maybe_derived_type,
229038fd1498Szrj otr_type);
229138fd1498Szrj
229238fd1498Szrj if (updated && dump_file && (dump_flags & TDF_DETAILS))
229338fd1498Szrj {
229438fd1498Szrj fprintf (dump_file, "Updated as: ");
229538fd1498Szrj dump (dump_file);
229638fd1498Szrj fprintf (dump_file, "\n");
229738fd1498Szrj }
229838fd1498Szrj return updated;
229938fd1498Szrj
230038fd1498Szrj invalidate:
230138fd1498Szrj invalid = true;
230238fd1498Szrj clear_speculation ();
230338fd1498Szrj clear_outer_type ();
230438fd1498Szrj return true;
230538fd1498Szrj }
230638fd1498Szrj
230738fd1498Szrj /* Take non-speculative info, merge it with speculative and clear speculation.
230838fd1498Szrj Used when we no longer manage to keep track of actual outer type, but we
230938fd1498Szrj think it is still there.
231038fd1498Szrj
231138fd1498Szrj If OTR_TYPE is set, the transformation can be done more effectively assuming
231238fd1498Szrj that context is going to be used only that way. */
231338fd1498Szrj
231438fd1498Szrj void
make_speculative(tree otr_type)231538fd1498Szrj ipa_polymorphic_call_context::make_speculative (tree otr_type)
231638fd1498Szrj {
231738fd1498Szrj tree spec_outer_type = outer_type;
231838fd1498Szrj HOST_WIDE_INT spec_offset = offset;
231938fd1498Szrj bool spec_maybe_derived_type = maybe_derived_type;
232038fd1498Szrj
232138fd1498Szrj if (invalid)
232238fd1498Szrj {
232338fd1498Szrj invalid = false;
232438fd1498Szrj clear_outer_type ();
232538fd1498Szrj clear_speculation ();
232638fd1498Szrj return;
232738fd1498Szrj }
232838fd1498Szrj if (!outer_type)
232938fd1498Szrj return;
233038fd1498Szrj clear_outer_type ();
233138fd1498Szrj combine_speculation_with (spec_outer_type, spec_offset,
233238fd1498Szrj spec_maybe_derived_type,
233338fd1498Szrj otr_type);
233438fd1498Szrj }
233538fd1498Szrj
233638fd1498Szrj /* Use when we can not track dynamic type change. This speculatively assume
233738fd1498Szrj type change is not happening. */
233838fd1498Szrj
233938fd1498Szrj void
possible_dynamic_type_change(bool in_poly_cdtor,tree otr_type)234038fd1498Szrj ipa_polymorphic_call_context::possible_dynamic_type_change (bool in_poly_cdtor,
234138fd1498Szrj tree otr_type)
234238fd1498Szrj {
234338fd1498Szrj if (dynamic)
234438fd1498Szrj make_speculative (otr_type);
234538fd1498Szrj else if (in_poly_cdtor)
234638fd1498Szrj maybe_in_construction = true;
234738fd1498Szrj }
234838fd1498Szrj
234938fd1498Szrj /* Return TRUE if this context conveys the same information as OTHER. */
235038fd1498Szrj
235138fd1498Szrj bool
equal_to(const ipa_polymorphic_call_context & x)235238fd1498Szrj ipa_polymorphic_call_context::equal_to
235338fd1498Szrj (const ipa_polymorphic_call_context &x) const
235438fd1498Szrj {
235538fd1498Szrj if (useless_p ())
235638fd1498Szrj return x.useless_p ();
235738fd1498Szrj if (invalid)
235838fd1498Szrj return x.invalid;
235938fd1498Szrj if (x.useless_p () || x.invalid)
236038fd1498Szrj return false;
236138fd1498Szrj
236238fd1498Szrj if (outer_type)
236338fd1498Szrj {
236438fd1498Szrj if (!x.outer_type
236538fd1498Szrj || !types_odr_comparable (outer_type, x.outer_type)
236638fd1498Szrj || !types_same_for_odr (outer_type, x.outer_type)
236738fd1498Szrj || offset != x.offset
236838fd1498Szrj || maybe_in_construction != x.maybe_in_construction
236938fd1498Szrj || maybe_derived_type != x.maybe_derived_type
237038fd1498Szrj || dynamic != x.dynamic)
237138fd1498Szrj return false;
237238fd1498Szrj }
237338fd1498Szrj else if (x.outer_type)
237438fd1498Szrj return false;
237538fd1498Szrj
237638fd1498Szrj
237738fd1498Szrj if (speculative_outer_type
237838fd1498Szrj && speculation_consistent_p (speculative_outer_type, speculative_offset,
237938fd1498Szrj speculative_maybe_derived_type, NULL_TREE))
238038fd1498Szrj {
238138fd1498Szrj if (!x.speculative_outer_type)
238238fd1498Szrj return false;
238338fd1498Szrj
238438fd1498Szrj if (!types_odr_comparable (speculative_outer_type,
238538fd1498Szrj x.speculative_outer_type)
238638fd1498Szrj || !types_same_for_odr (speculative_outer_type,
238738fd1498Szrj x.speculative_outer_type)
238838fd1498Szrj || speculative_offset != x.speculative_offset
238938fd1498Szrj || speculative_maybe_derived_type != x.speculative_maybe_derived_type)
239038fd1498Szrj return false;
239138fd1498Szrj }
239238fd1498Szrj else if (x.speculative_outer_type
239338fd1498Szrj && x.speculation_consistent_p (x.speculative_outer_type,
239438fd1498Szrj x.speculative_offset,
239538fd1498Szrj x.speculative_maybe_derived_type,
239638fd1498Szrj NULL))
239738fd1498Szrj return false;
239838fd1498Szrj
239938fd1498Szrj return true;
240038fd1498Szrj }
240138fd1498Szrj
240238fd1498Szrj /* Modify context to be strictly less restrictive than CTX. */
240338fd1498Szrj
240438fd1498Szrj bool
meet_with(ipa_polymorphic_call_context ctx,tree otr_type)240538fd1498Szrj ipa_polymorphic_call_context::meet_with (ipa_polymorphic_call_context ctx,
240638fd1498Szrj tree otr_type)
240738fd1498Szrj {
240838fd1498Szrj bool updated = false;
240938fd1498Szrj
241038fd1498Szrj if (useless_p () || ctx.invalid)
241138fd1498Szrj return false;
241238fd1498Szrj
241338fd1498Szrj /* Restricting context to inner type makes merging easier, however do not
241438fd1498Szrj do that unless we know how the context is used (OTR_TYPE is non-NULL) */
241538fd1498Szrj if (otr_type && !useless_p () && !ctx.useless_p ())
241638fd1498Szrj {
241738fd1498Szrj restrict_to_inner_class (otr_type);
241838fd1498Szrj ctx.restrict_to_inner_class (otr_type);
241938fd1498Szrj if(invalid)
242038fd1498Szrj return false;
242138fd1498Szrj }
242238fd1498Szrj
242338fd1498Szrj if (equal_to (ctx))
242438fd1498Szrj return false;
242538fd1498Szrj
242638fd1498Szrj if (ctx.useless_p () || invalid)
242738fd1498Szrj {
242838fd1498Szrj *this = ctx;
242938fd1498Szrj return true;
243038fd1498Szrj }
243138fd1498Szrj
243238fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
243338fd1498Szrj {
243438fd1498Szrj fprintf (dump_file, "Polymorphic call context meet:");
243538fd1498Szrj dump (dump_file);
243638fd1498Szrj fprintf (dump_file, "With context: ");
243738fd1498Szrj ctx.dump (dump_file);
243838fd1498Szrj if (otr_type)
243938fd1498Szrj {
244038fd1498Szrj fprintf (dump_file, "To be used with type: ");
244138fd1498Szrj print_generic_expr (dump_file, otr_type, TDF_SLIM);
244238fd1498Szrj fprintf (dump_file, "\n");
244338fd1498Szrj }
244438fd1498Szrj }
244538fd1498Szrj
244638fd1498Szrj if (!dynamic && ctx.dynamic)
244738fd1498Szrj {
244838fd1498Szrj dynamic = true;
244938fd1498Szrj updated = true;
245038fd1498Szrj }
245138fd1498Szrj
245238fd1498Szrj /* If call is known to be invalid, we are done. */
245338fd1498Szrj if (!outer_type)
245438fd1498Szrj ;
245538fd1498Szrj else if (!ctx.outer_type)
245638fd1498Szrj {
245738fd1498Szrj clear_outer_type ();
245838fd1498Szrj updated = true;
245938fd1498Szrj }
246038fd1498Szrj /* If types are known to be same, merging is quite easy. */
246138fd1498Szrj else if (types_must_be_same_for_odr (outer_type, ctx.outer_type))
246238fd1498Szrj {
246338fd1498Szrj if (offset != ctx.offset
246438fd1498Szrj && TYPE_SIZE (outer_type)
246538fd1498Szrj && TREE_CODE (TYPE_SIZE (outer_type)) == INTEGER_CST)
246638fd1498Szrj {
246738fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
246838fd1498Szrj fprintf (dump_file, "Outer types match, offset mismatch -> clearing\n");
246938fd1498Szrj clear_outer_type ();
247038fd1498Szrj return true;
247138fd1498Szrj }
247238fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
247338fd1498Szrj fprintf (dump_file, "Outer types match, merging flags\n");
247438fd1498Szrj if (!maybe_in_construction && ctx.maybe_in_construction)
247538fd1498Szrj {
247638fd1498Szrj updated = true;
247738fd1498Szrj maybe_in_construction = true;
247838fd1498Szrj }
247938fd1498Szrj if (!maybe_derived_type && ctx.maybe_derived_type)
248038fd1498Szrj {
248138fd1498Szrj updated = true;
248238fd1498Szrj maybe_derived_type = true;
248338fd1498Szrj }
248438fd1498Szrj if (!dynamic && ctx.dynamic)
248538fd1498Szrj {
248638fd1498Szrj updated = true;
248738fd1498Szrj dynamic = true;
248838fd1498Szrj }
248938fd1498Szrj }
249038fd1498Szrj /* See if one type contains the other as a field (not base). */
249138fd1498Szrj else if (contains_type_p (ctx.outer_type, ctx.offset - offset,
249238fd1498Szrj outer_type, false, false))
249338fd1498Szrj {
249438fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
249538fd1498Szrj fprintf (dump_file, "Second type contain the first as a field\n");
249638fd1498Szrj
249738fd1498Szrj /* The second type is more specified, so we keep the first.
249838fd1498Szrj We need to set DYNAMIC flag to avoid declaring context INVALID
249938fd1498Szrj of OFFSET ends up being out of range. */
250038fd1498Szrj if (!dynamic
250138fd1498Szrj && (ctx.dynamic
250238fd1498Szrj || (!otr_type
250338fd1498Szrj && (!TYPE_SIZE (ctx.outer_type)
250438fd1498Szrj || !TYPE_SIZE (outer_type)
250538fd1498Szrj || !operand_equal_p (TYPE_SIZE (ctx.outer_type),
250638fd1498Szrj TYPE_SIZE (outer_type), 0)))))
250738fd1498Szrj {
250838fd1498Szrj dynamic = true;
250938fd1498Szrj updated = true;
251038fd1498Szrj }
251138fd1498Szrj }
251238fd1498Szrj else if (contains_type_p (outer_type, offset - ctx.offset,
251338fd1498Szrj ctx.outer_type, false, false))
251438fd1498Szrj {
251538fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
251638fd1498Szrj fprintf (dump_file, "First type contain the second as a field\n");
251738fd1498Szrj
251838fd1498Szrj if (!dynamic
251938fd1498Szrj && (ctx.dynamic
252038fd1498Szrj || (!otr_type
252138fd1498Szrj && (!TYPE_SIZE (ctx.outer_type)
252238fd1498Szrj || !TYPE_SIZE (outer_type)
252338fd1498Szrj || !operand_equal_p (TYPE_SIZE (ctx.outer_type),
252438fd1498Szrj TYPE_SIZE (outer_type), 0)))))
252538fd1498Szrj dynamic = true;
252638fd1498Szrj outer_type = ctx.outer_type;
252738fd1498Szrj offset = ctx.offset;
252838fd1498Szrj dynamic = ctx.dynamic;
252938fd1498Szrj maybe_in_construction = ctx.maybe_in_construction;
253038fd1498Szrj maybe_derived_type = ctx.maybe_derived_type;
253138fd1498Szrj updated = true;
253238fd1498Szrj }
253338fd1498Szrj /* See if OUTER_TYPE is base of CTX.OUTER_TYPE. */
253438fd1498Szrj else if (contains_type_p (ctx.outer_type,
253538fd1498Szrj ctx.offset - offset, outer_type, false, true))
253638fd1498Szrj {
253738fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
253838fd1498Szrj fprintf (dump_file, "First type is base of second\n");
253938fd1498Szrj if (!maybe_derived_type)
254038fd1498Szrj {
254138fd1498Szrj maybe_derived_type = true;
254238fd1498Szrj updated = true;
254338fd1498Szrj }
254438fd1498Szrj if (!maybe_in_construction && ctx.maybe_in_construction)
254538fd1498Szrj {
254638fd1498Szrj maybe_in_construction = true;
254738fd1498Szrj updated = true;
254838fd1498Szrj }
254938fd1498Szrj if (!dynamic && ctx.dynamic)
255038fd1498Szrj {
255138fd1498Szrj dynamic = true;
255238fd1498Szrj updated = true;
255338fd1498Szrj }
255438fd1498Szrj }
255538fd1498Szrj /* See if CTX.OUTER_TYPE is base of OUTER_TYPE. */
255638fd1498Szrj else if (contains_type_p (outer_type,
255738fd1498Szrj offset - ctx.offset, ctx.outer_type, false, true))
255838fd1498Szrj {
255938fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
256038fd1498Szrj fprintf (dump_file, "Second type is base of first\n");
256138fd1498Szrj outer_type = ctx.outer_type;
256238fd1498Szrj offset = ctx.offset;
256338fd1498Szrj updated = true;
256438fd1498Szrj if (!maybe_derived_type)
256538fd1498Szrj maybe_derived_type = true;
256638fd1498Szrj if (!maybe_in_construction && ctx.maybe_in_construction)
256738fd1498Szrj maybe_in_construction = true;
256838fd1498Szrj if (!dynamic && ctx.dynamic)
256938fd1498Szrj dynamic = true;
257038fd1498Szrj }
257138fd1498Szrj /* TODO handle merging using hiearchy. */
257238fd1498Szrj else
257338fd1498Szrj {
257438fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
257538fd1498Szrj fprintf (dump_file, "Giving up on meet\n");
257638fd1498Szrj clear_outer_type ();
257738fd1498Szrj updated = true;
257838fd1498Szrj }
257938fd1498Szrj
258038fd1498Szrj updated |= meet_speculation_with (ctx.speculative_outer_type,
258138fd1498Szrj ctx.speculative_offset,
258238fd1498Szrj ctx.speculative_maybe_derived_type,
258338fd1498Szrj otr_type);
258438fd1498Szrj
258538fd1498Szrj if (updated && dump_file && (dump_flags & TDF_DETAILS))
258638fd1498Szrj {
258738fd1498Szrj fprintf (dump_file, "Updated as: ");
258838fd1498Szrj dump (dump_file);
258938fd1498Szrj fprintf (dump_file, "\n");
259038fd1498Szrj }
259138fd1498Szrj return updated;
259238fd1498Szrj }
2593