xref: /dflybsd-src/contrib/gcc-8.0/gcc/ipa-polymorphic-call.c (revision 95059079af47f9a66a175f374f2da1a5020e3255)
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