110d565efSmrg /* Analysis of polymorphic call context.
2*ec02198aSmrg    Copyright (C) 2013-2020 Free Software Foundation, Inc.
310d565efSmrg    Contributed by Jan Hubicka
410d565efSmrg 
510d565efSmrg This file is part of GCC.
610d565efSmrg 
710d565efSmrg GCC is free software; you can redistribute it and/or modify it under
810d565efSmrg the terms of the GNU General Public License as published by the Free
910d565efSmrg Software Foundation; either version 3, or (at your option) any later
1010d565efSmrg version.
1110d565efSmrg 
1210d565efSmrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
1310d565efSmrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
1410d565efSmrg FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1510d565efSmrg for more details.
1610d565efSmrg 
1710d565efSmrg You should have received a copy of the GNU General Public License
1810d565efSmrg along with GCC; see the file COPYING3.  If not see
1910d565efSmrg <http://www.gnu.org/licenses/>.  */
2010d565efSmrg 
2110d565efSmrg #include "config.h"
2210d565efSmrg #include "system.h"
2310d565efSmrg #include "coretypes.h"
2410d565efSmrg #include "backend.h"
2510d565efSmrg #include "rtl.h"
2610d565efSmrg #include "tree.h"
2710d565efSmrg #include "gimple.h"
2810d565efSmrg #include "tree-pass.h"
2910d565efSmrg #include "tree-ssa-operands.h"
3010d565efSmrg #include "streamer-hooks.h"
3110d565efSmrg #include "cgraph.h"
3210d565efSmrg #include "data-streamer.h"
3310d565efSmrg #include "diagnostic.h"
3410d565efSmrg #include "alias.h"
3510d565efSmrg #include "fold-const.h"
3610d565efSmrg #include "calls.h"
3710d565efSmrg #include "ipa-utils.h"
3810d565efSmrg #include "tree-dfa.h"
3910d565efSmrg #include "gimple-pretty-print.h"
4010d565efSmrg #include "tree-into-ssa.h"
4110d565efSmrg 
4210d565efSmrg /* Return true when TYPE contains an polymorphic type and thus is interesting
4310d565efSmrg    for devirtualization machinery.  */
4410d565efSmrg 
4510d565efSmrg static bool contains_type_p (tree, HOST_WIDE_INT, tree,
4610d565efSmrg 			     bool consider_placement_new = true,
4710d565efSmrg 			     bool consider_bases = true);
4810d565efSmrg 
4910d565efSmrg bool
contains_polymorphic_type_p(const_tree type)5010d565efSmrg contains_polymorphic_type_p (const_tree type)
5110d565efSmrg {
5210d565efSmrg   type = TYPE_MAIN_VARIANT (type);
5310d565efSmrg 
5410d565efSmrg   if (RECORD_OR_UNION_TYPE_P (type))
5510d565efSmrg     {
5610d565efSmrg       if (TYPE_BINFO (type)
5710d565efSmrg           && polymorphic_type_binfo_p (TYPE_BINFO (type)))
5810d565efSmrg 	return true;
5910d565efSmrg       for (tree fld = TYPE_FIELDS (type); fld; fld = DECL_CHAIN (fld))
6010d565efSmrg 	if (TREE_CODE (fld) == FIELD_DECL
6110d565efSmrg 	    && !DECL_ARTIFICIAL (fld)
6210d565efSmrg 	    && contains_polymorphic_type_p (TREE_TYPE (fld)))
6310d565efSmrg 	  return true;
6410d565efSmrg       return false;
6510d565efSmrg     }
6610d565efSmrg   if (TREE_CODE (type) == ARRAY_TYPE)
6710d565efSmrg     return contains_polymorphic_type_p (TREE_TYPE (type));
6810d565efSmrg   return false;
6910d565efSmrg }
7010d565efSmrg 
7110d565efSmrg /* Return true if it seems valid to use placement new to build EXPECTED_TYPE
72*ec02198aSmrg    at position CUR_OFFSET within TYPE.
7310d565efSmrg 
7410d565efSmrg    POD can be changed to an instance of a polymorphic type by
7510d565efSmrg    placement new.  Here we play safe and assume that any
7610d565efSmrg    non-polymorphic type is POD.  */
7710d565efSmrg bool
possible_placement_new(tree type,tree expected_type,HOST_WIDE_INT cur_offset)7810d565efSmrg possible_placement_new (tree type, tree expected_type,
7910d565efSmrg 			HOST_WIDE_INT cur_offset)
8010d565efSmrg {
8110d565efSmrg   if (cur_offset < 0)
8210d565efSmrg     return true;
8310d565efSmrg   return ((TREE_CODE (type) != RECORD_TYPE
8410d565efSmrg 	   || !TYPE_BINFO (type)
8510d565efSmrg 	   || cur_offset >= POINTER_SIZE
8610d565efSmrg 	   || !polymorphic_type_binfo_p (TYPE_BINFO (type)))
8710d565efSmrg 	  && (!TYPE_SIZE (type)
8810d565efSmrg 	      || !tree_fits_shwi_p (TYPE_SIZE (type))
8910d565efSmrg 	      || (cur_offset
9010d565efSmrg 		  + (expected_type ? tree_to_uhwi (TYPE_SIZE (expected_type))
9110d565efSmrg 		     : POINTER_SIZE)
9210d565efSmrg 		  <= tree_to_uhwi (TYPE_SIZE (type)))));
9310d565efSmrg }
9410d565efSmrg 
9510d565efSmrg /* THIS->OUTER_TYPE is a type of memory object where object of OTR_TYPE
9610d565efSmrg    is contained at THIS->OFFSET.  Walk the memory representation of
9710d565efSmrg    THIS->OUTER_TYPE and find the outermost class type that match
9810d565efSmrg    OTR_TYPE or contain OTR_TYPE as a base.  Update THIS
9910d565efSmrg    to represent it.
10010d565efSmrg 
10110d565efSmrg    If OTR_TYPE is NULL, just find outermost polymorphic type with
102*ec02198aSmrg    virtual table present at position OFFSET.
10310d565efSmrg 
10410d565efSmrg    For example when THIS represents type
10510d565efSmrg    class A
10610d565efSmrg      {
10710d565efSmrg        int a;
10810d565efSmrg        class B b;
10910d565efSmrg      }
11010d565efSmrg    and we look for type at offset sizeof(int), we end up with B and offset 0.
11110d565efSmrg    If the same is produced by multiple inheritance, we end up with A and offset
11210d565efSmrg    sizeof(int).
11310d565efSmrg 
11410d565efSmrg    If we cannot find corresponding class, give up by setting
11510d565efSmrg    THIS->OUTER_TYPE to OTR_TYPE and THIS->OFFSET to NULL.
116*ec02198aSmrg    Return true when lookup was successful.
11710d565efSmrg 
11810d565efSmrg    When CONSIDER_PLACEMENT_NEW is false, reject contexts that may be made
11910d565efSmrg    valid only via allocation of new polymorphic type inside by means
12010d565efSmrg    of placement new.
12110d565efSmrg 
12210d565efSmrg    When CONSIDER_BASES is false, only look for actual fields, not base types
12310d565efSmrg    of TYPE.  */
12410d565efSmrg 
12510d565efSmrg bool
restrict_to_inner_class(tree otr_type,bool consider_placement_new,bool consider_bases)12610d565efSmrg ipa_polymorphic_call_context::restrict_to_inner_class (tree otr_type,
12710d565efSmrg 						       bool consider_placement_new,
12810d565efSmrg 						       bool consider_bases)
12910d565efSmrg {
13010d565efSmrg   tree type = outer_type;
13110d565efSmrg   HOST_WIDE_INT cur_offset = offset;
13210d565efSmrg   bool speculative = false;
13310d565efSmrg   bool size_unknown = false;
13410d565efSmrg   unsigned HOST_WIDE_INT otr_type_size = POINTER_SIZE;
13510d565efSmrg 
13610d565efSmrg   /* Update OUTER_TYPE to match EXPECTED_TYPE if it is not set.  */
13710d565efSmrg   if (!outer_type)
13810d565efSmrg     {
13910d565efSmrg       clear_outer_type (otr_type);
14010d565efSmrg       type = otr_type;
14110d565efSmrg       cur_offset = 0;
14210d565efSmrg     }
14310d565efSmrg  /* See if OFFSET points inside OUTER_TYPE.  If it does not, we know
14410d565efSmrg     that the context is either invalid, or the instance type must be
14510d565efSmrg     derived from OUTER_TYPE.
14610d565efSmrg 
14710d565efSmrg     Because the instance type may contain field whose type is of OUTER_TYPE,
14810d565efSmrg     we cannot derive any effective information about it.
14910d565efSmrg 
150*ec02198aSmrg     TODO: In the case we know all derived types, we can definitely do better
15110d565efSmrg     here.  */
15210d565efSmrg   else if (TYPE_SIZE (outer_type)
15310d565efSmrg 	   && tree_fits_shwi_p (TYPE_SIZE (outer_type))
15410d565efSmrg 	   && tree_to_shwi (TYPE_SIZE (outer_type)) >= 0
15510d565efSmrg 	   && tree_to_shwi (TYPE_SIZE (outer_type)) <= offset)
15610d565efSmrg    {
15710d565efSmrg      bool der = maybe_derived_type; /* clear_outer_type will reset it.  */
15810d565efSmrg      bool dyn = dynamic;
15910d565efSmrg      clear_outer_type (otr_type);
16010d565efSmrg      type = otr_type;
16110d565efSmrg      cur_offset = 0;
16210d565efSmrg 
16310d565efSmrg      /* If derived type is not allowed, we know that the context is invalid.
16410d565efSmrg 	For dynamic types, we really do not have information about
16510d565efSmrg 	size of the memory location.  It is possible that completely
16610d565efSmrg 	different type is stored after outer_type.  */
16710d565efSmrg      if (!der && !dyn)
16810d565efSmrg        {
16910d565efSmrg 	 clear_speculation ();
17010d565efSmrg 	 invalid = true;
17110d565efSmrg 	 return false;
17210d565efSmrg        }
17310d565efSmrg    }
17410d565efSmrg 
17510d565efSmrg   if (otr_type && TYPE_SIZE (otr_type)
17610d565efSmrg       && tree_fits_shwi_p (TYPE_SIZE (otr_type)))
17710d565efSmrg     otr_type_size = tree_to_uhwi (TYPE_SIZE (otr_type));
17810d565efSmrg 
17910d565efSmrg   if (!type || offset < 0)
18010d565efSmrg     goto no_useful_type_info;
18110d565efSmrg 
18210d565efSmrg   /* Find the sub-object the constant actually refers to and mark whether it is
18310d565efSmrg      an artificial one (as opposed to a user-defined one).
18410d565efSmrg 
18510d565efSmrg      This loop is performed twice; first time for outer_type and second time
18610d565efSmrg      for speculative_outer_type.  The second run has SPECULATIVE set.  */
18710d565efSmrg   while (true)
18810d565efSmrg     {
18910d565efSmrg       unsigned HOST_WIDE_INT pos, size;
19010d565efSmrg       tree fld;
19110d565efSmrg 
19210d565efSmrg       /* If we do not know size of TYPE, we need to be more conservative
19310d565efSmrg          about accepting cases where we cannot find EXPECTED_TYPE.
19410d565efSmrg 	 Generally the types that do matter here are of constant size.
19510d565efSmrg 	 Size_unknown case should be very rare.  */
19610d565efSmrg       if (TYPE_SIZE (type)
19710d565efSmrg 	  && tree_fits_shwi_p (TYPE_SIZE (type))
19810d565efSmrg 	  && tree_to_shwi (TYPE_SIZE (type)) >= 0)
19910d565efSmrg 	size_unknown = false;
20010d565efSmrg       else
20110d565efSmrg 	size_unknown = true;
20210d565efSmrg 
20310d565efSmrg       /* On a match, just return what we found.  */
20410d565efSmrg       if ((otr_type
20510d565efSmrg 	   && types_odr_comparable (type, otr_type)
20610d565efSmrg 	   && types_same_for_odr (type, otr_type))
20710d565efSmrg 	  || (!otr_type
20810d565efSmrg 	      && TREE_CODE (type) == RECORD_TYPE
20910d565efSmrg 	      && TYPE_BINFO (type)
21010d565efSmrg 	      && polymorphic_type_binfo_p (TYPE_BINFO (type))))
21110d565efSmrg 	{
21210d565efSmrg 	  if (speculative)
21310d565efSmrg 	    {
21410d565efSmrg 	      /* If we did not match the offset, just give up on speculation.  */
21510d565efSmrg 	      if (cur_offset != 0
21610d565efSmrg 		  /* Also check if speculation did not end up being same as
21710d565efSmrg 		     non-speculation.  */
21810d565efSmrg 		  || (types_must_be_same_for_odr (speculative_outer_type,
21910d565efSmrg 						  outer_type)
22010d565efSmrg 		      && (maybe_derived_type
22110d565efSmrg 			  == speculative_maybe_derived_type)))
22210d565efSmrg 		clear_speculation ();
22310d565efSmrg 	      return true;
22410d565efSmrg 	    }
22510d565efSmrg 	  else
22610d565efSmrg 	    {
22710d565efSmrg 	      /* If type is known to be final, do not worry about derived
22810d565efSmrg 		 types.  Testing it here may help us to avoid speculation.  */
22910d565efSmrg 	      if (otr_type && TREE_CODE (outer_type) == RECORD_TYPE
23010d565efSmrg 		  && (!in_lto_p || odr_type_p (outer_type))
23110d565efSmrg 		  && type_with_linkage_p (outer_type)
23210d565efSmrg 		  && type_known_to_have_no_derivations_p (outer_type))
23310d565efSmrg 		maybe_derived_type = false;
23410d565efSmrg 
23510d565efSmrg 	      /* Type cannot contain itself on an non-zero offset.  In that case
23610d565efSmrg 		 just give up.  Still accept the case where size is now known.
23710d565efSmrg 		 Either the second copy may appear past the end of type or within
23810d565efSmrg 		 the non-POD buffer located inside the variably sized type
23910d565efSmrg 		 itself.  */
24010d565efSmrg 	      if (cur_offset != 0)
24110d565efSmrg 		goto no_useful_type_info;
24210d565efSmrg 	      /* If we determined type precisely or we have no clue on
243*ec02198aSmrg  		 speculation, we are done.  */
24410d565efSmrg 	      if (!maybe_derived_type || !speculative_outer_type
24510d565efSmrg 		  || !speculation_consistent_p (speculative_outer_type,
24610d565efSmrg 					        speculative_offset,
24710d565efSmrg 					        speculative_maybe_derived_type,
24810d565efSmrg 						otr_type))
24910d565efSmrg 		{
25010d565efSmrg 		  clear_speculation ();
25110d565efSmrg 	          return true;
25210d565efSmrg 		}
25310d565efSmrg 	      /* Otherwise look into speculation now.  */
25410d565efSmrg 	      else
25510d565efSmrg 		{
25610d565efSmrg 		  speculative = true;
25710d565efSmrg 		  type = speculative_outer_type;
25810d565efSmrg 		  cur_offset = speculative_offset;
25910d565efSmrg 		  continue;
26010d565efSmrg 		}
26110d565efSmrg 	    }
26210d565efSmrg 	}
26310d565efSmrg 
26410d565efSmrg       /* Walk fields and find corresponding on at OFFSET.  */
26510d565efSmrg       if (TREE_CODE (type) == RECORD_TYPE)
26610d565efSmrg 	{
26710d565efSmrg 	  for (fld = TYPE_FIELDS (type); fld; fld = DECL_CHAIN (fld))
26810d565efSmrg 	    {
26910d565efSmrg 	      if (TREE_CODE (fld) != FIELD_DECL
27010d565efSmrg 		  || TREE_TYPE (fld) == error_mark_node)
27110d565efSmrg 		continue;
27210d565efSmrg 
27310d565efSmrg 	      pos = int_bit_position (fld);
27410d565efSmrg 	      if (pos > (unsigned HOST_WIDE_INT)cur_offset)
27510d565efSmrg 		continue;
27610d565efSmrg 
27710d565efSmrg 	      /* Do not consider vptr itself.  Not even for placement new.  */
27810d565efSmrg 	      if (!pos && DECL_ARTIFICIAL (fld)
27910d565efSmrg 		  && POINTER_TYPE_P (TREE_TYPE (fld))
28010d565efSmrg 		  && TYPE_BINFO (type)
28110d565efSmrg 		  && polymorphic_type_binfo_p (TYPE_BINFO (type)))
28210d565efSmrg 		continue;
28310d565efSmrg 
28410d565efSmrg 	      if (!DECL_SIZE (fld) || !tree_fits_uhwi_p (DECL_SIZE (fld)))
28510d565efSmrg 		goto no_useful_type_info;
28610d565efSmrg 	      size = tree_to_uhwi (DECL_SIZE (fld));
28710d565efSmrg 
28810d565efSmrg 	      /* We can always skip types smaller than pointer size:
28910d565efSmrg 		 those cannot contain a virtual table pointer.
29010d565efSmrg 
29110d565efSmrg 		 Disqualifying fields that are too small to fit OTR_TYPE
29210d565efSmrg 		 saves work needed to walk them for no benefit.
29310d565efSmrg 		 Because of the way the bases are packed into a class, the
29410d565efSmrg 		 field's size may be smaller than type size, so it needs
29510d565efSmrg 		 to be done with a care.  */
29610d565efSmrg 
29710d565efSmrg 	      if (pos <= (unsigned HOST_WIDE_INT)cur_offset
29810d565efSmrg 		  && (pos + size) >= (unsigned HOST_WIDE_INT)cur_offset
29910d565efSmrg 				     + POINTER_SIZE
30010d565efSmrg 		  && (!otr_type
30110d565efSmrg 		      || !TYPE_SIZE (TREE_TYPE (fld))
30210d565efSmrg 		      || !tree_fits_shwi_p (TYPE_SIZE (TREE_TYPE (fld)))
30310d565efSmrg 		      || (pos + tree_to_uhwi (TYPE_SIZE (TREE_TYPE (fld))))
30410d565efSmrg 			  >= cur_offset + otr_type_size))
30510d565efSmrg 		break;
30610d565efSmrg 	    }
30710d565efSmrg 
30810d565efSmrg 	  if (!fld)
30910d565efSmrg 	    goto no_useful_type_info;
31010d565efSmrg 
31110d565efSmrg 	  type = TYPE_MAIN_VARIANT (TREE_TYPE (fld));
31210d565efSmrg 	  cur_offset -= pos;
31310d565efSmrg 	  /* DECL_ARTIFICIAL represents a basetype.  */
31410d565efSmrg 	  if (!DECL_ARTIFICIAL (fld))
31510d565efSmrg 	    {
31610d565efSmrg 	      if (!speculative)
31710d565efSmrg 		{
31810d565efSmrg 		  outer_type = type;
31910d565efSmrg 		  offset = cur_offset;
320*ec02198aSmrg 		  /* As soon as we see an field containing the type,
32110d565efSmrg 		     we know we are not looking for derivations.  */
32210d565efSmrg 		  maybe_derived_type = false;
32310d565efSmrg 		}
32410d565efSmrg 	      else
32510d565efSmrg 		{
32610d565efSmrg 		  speculative_outer_type = type;
32710d565efSmrg 		  speculative_offset = cur_offset;
32810d565efSmrg 		  speculative_maybe_derived_type = false;
32910d565efSmrg 		}
33010d565efSmrg 	    }
33110d565efSmrg 	  else if (!consider_bases)
33210d565efSmrg 	    goto no_useful_type_info;
33310d565efSmrg 	}
33410d565efSmrg       else if (TREE_CODE (type) == ARRAY_TYPE)
33510d565efSmrg 	{
33610d565efSmrg 	  tree subtype = TYPE_MAIN_VARIANT (TREE_TYPE (type));
33710d565efSmrg 
33810d565efSmrg 	  /* Give up if we don't know array field size.
33910d565efSmrg 	     Also give up on non-polymorphic types as they are used
34010d565efSmrg 	     as buffers for placement new.  */
34110d565efSmrg 	  if (!TYPE_SIZE (subtype)
34210d565efSmrg 	      || !tree_fits_shwi_p (TYPE_SIZE (subtype))
34310d565efSmrg 	      || tree_to_shwi (TYPE_SIZE (subtype)) <= 0
34410d565efSmrg 	      || !contains_polymorphic_type_p (subtype))
34510d565efSmrg 	    goto no_useful_type_info;
34610d565efSmrg 
34710d565efSmrg 	  HOST_WIDE_INT new_offset = cur_offset % tree_to_shwi (TYPE_SIZE (subtype));
34810d565efSmrg 
34910d565efSmrg 	  /* We may see buffer for placement new.  In this case the expected type
35010d565efSmrg 	     can be bigger than the subtype.  */
35110d565efSmrg 	  if (TYPE_SIZE (subtype)
35210d565efSmrg 	      && (cur_offset + otr_type_size
35310d565efSmrg 		  > tree_to_uhwi (TYPE_SIZE (subtype))))
35410d565efSmrg 	    goto no_useful_type_info;
35510d565efSmrg 
35610d565efSmrg 	  cur_offset = new_offset;
35710d565efSmrg 	  type = TYPE_MAIN_VARIANT (subtype);
35810d565efSmrg 	  if (!speculative)
35910d565efSmrg 	    {
36010d565efSmrg 	      outer_type = type;
36110d565efSmrg 	      offset = cur_offset;
36210d565efSmrg 	      maybe_derived_type = false;
36310d565efSmrg 	    }
36410d565efSmrg 	  else
36510d565efSmrg 	    {
36610d565efSmrg 	      speculative_outer_type = type;
36710d565efSmrg 	      speculative_offset = cur_offset;
36810d565efSmrg 	      speculative_maybe_derived_type = false;
36910d565efSmrg 	    }
37010d565efSmrg 	}
37110d565efSmrg       /* Give up on anything else.  */
37210d565efSmrg       else
37310d565efSmrg 	{
37410d565efSmrg no_useful_type_info:
37510d565efSmrg 	  if (maybe_derived_type && !speculative
37610d565efSmrg 	      && TREE_CODE (outer_type) == RECORD_TYPE
37710d565efSmrg 	      && TREE_CODE (otr_type) == RECORD_TYPE
37810d565efSmrg 	      && TYPE_BINFO (otr_type)
37910d565efSmrg 	      && !offset
38010d565efSmrg 	      && get_binfo_at_offset (TYPE_BINFO (otr_type), 0, outer_type))
38110d565efSmrg 	    {
38210d565efSmrg 	      clear_outer_type (otr_type);
38310d565efSmrg 	      if (!speculative_outer_type
38410d565efSmrg 		  || !speculation_consistent_p (speculative_outer_type,
38510d565efSmrg 						speculative_offset,
38610d565efSmrg 					        speculative_maybe_derived_type,
38710d565efSmrg 						otr_type))
38810d565efSmrg 		clear_speculation ();
38910d565efSmrg 	      if (speculative_outer_type)
39010d565efSmrg 		{
39110d565efSmrg 		  speculative = true;
39210d565efSmrg 		  type = speculative_outer_type;
39310d565efSmrg 		  cur_offset = speculative_offset;
39410d565efSmrg 		}
39510d565efSmrg 	      else
39610d565efSmrg 		return true;
39710d565efSmrg 	    }
398*ec02198aSmrg 	  /* We found no way to embed EXPECTED_TYPE in TYPE.
39910d565efSmrg 	     We still permit two special cases - placement new and
40010d565efSmrg 	     the case of variadic types containing themselves.  */
40110d565efSmrg 	  if (!speculative
40210d565efSmrg 	      && consider_placement_new
40310d565efSmrg 	      && (size_unknown || !type || maybe_derived_type
40410d565efSmrg 		  || possible_placement_new (type, otr_type, cur_offset)))
40510d565efSmrg 	    {
40610d565efSmrg 	      /* In these weird cases we want to accept the context.
40710d565efSmrg 		 In non-speculative run we have no useful outer_type info
40810d565efSmrg 		 (TODO: we may eventually want to record upper bound on the
40910d565efSmrg 		  type size that can be used to prune the walk),
41010d565efSmrg 		 but we still want to consider speculation that may
41110d565efSmrg 		 give useful info.  */
41210d565efSmrg 	      if (!speculative)
41310d565efSmrg 		{
41410d565efSmrg 		  clear_outer_type (otr_type);
41510d565efSmrg 		  if (!speculative_outer_type
41610d565efSmrg 		      || !speculation_consistent_p (speculative_outer_type,
41710d565efSmrg 						    speculative_offset,
41810d565efSmrg 						    speculative_maybe_derived_type,
41910d565efSmrg 						    otr_type))
42010d565efSmrg 		    clear_speculation ();
42110d565efSmrg 		  if (speculative_outer_type)
42210d565efSmrg 		    {
42310d565efSmrg 		      speculative = true;
42410d565efSmrg 		      type = speculative_outer_type;
42510d565efSmrg 		      cur_offset = speculative_offset;
42610d565efSmrg 		    }
42710d565efSmrg 		  else
42810d565efSmrg 		    return true;
42910d565efSmrg 		}
43010d565efSmrg 	      else
43110d565efSmrg 		{
43210d565efSmrg 		  clear_speculation ();
43310d565efSmrg 	          return true;
43410d565efSmrg 		}
43510d565efSmrg 	    }
43610d565efSmrg 	  else
43710d565efSmrg 	    {
43810d565efSmrg 	      clear_speculation ();
43910d565efSmrg 	      if (speculative)
44010d565efSmrg 		return true;
44110d565efSmrg 	      clear_outer_type (otr_type);
44210d565efSmrg 	      invalid = true;
44310d565efSmrg 	      return false;
44410d565efSmrg 	    }
44510d565efSmrg 	}
44610d565efSmrg     }
44710d565efSmrg }
44810d565efSmrg 
44910d565efSmrg /* Return true if OUTER_TYPE contains OTR_TYPE at OFFSET.
45010d565efSmrg    CONSIDER_PLACEMENT_NEW makes function to accept cases where OTR_TYPE can
45110d565efSmrg    be built within OUTER_TYPE by means of placement new.  CONSIDER_BASES makes
45210d565efSmrg    function to accept cases where OTR_TYPE appears as base of OUTER_TYPE or as
45310d565efSmrg    base of one of fields of OUTER_TYPE.  */
45410d565efSmrg 
45510d565efSmrg static bool
contains_type_p(tree outer_type,HOST_WIDE_INT offset,tree otr_type,bool consider_placement_new,bool consider_bases)45610d565efSmrg contains_type_p (tree outer_type, HOST_WIDE_INT offset,
45710d565efSmrg 		 tree otr_type,
45810d565efSmrg 		 bool consider_placement_new,
45910d565efSmrg 		 bool consider_bases)
46010d565efSmrg {
46110d565efSmrg   ipa_polymorphic_call_context context;
46210d565efSmrg 
46310d565efSmrg   /* Check that type is within range.  */
46410d565efSmrg   if (offset < 0)
46510d565efSmrg     return false;
46610d565efSmrg 
46710d565efSmrg   /* PR ipa/71207
46810d565efSmrg      As OUTER_TYPE can be a type which has a diamond virtual inheritance,
46910d565efSmrg      it's not necessary that INNER_TYPE will fit within OUTER_TYPE with
47010d565efSmrg      a given offset.  It can happen that INNER_TYPE also contains a base object,
47110d565efSmrg      however it would point to the same instance in the OUTER_TYPE.  */
47210d565efSmrg 
47310d565efSmrg   context.offset = offset;
47410d565efSmrg   context.outer_type = TYPE_MAIN_VARIANT (outer_type);
47510d565efSmrg   context.maybe_derived_type = false;
47610d565efSmrg   context.dynamic = false;
47710d565efSmrg   return context.restrict_to_inner_class (otr_type, consider_placement_new,
47810d565efSmrg 					  consider_bases);
47910d565efSmrg }
48010d565efSmrg 
48110d565efSmrg 
48210d565efSmrg /* Return a FUNCTION_DECL if FN represent a constructor or destructor.
48310d565efSmrg    If CHECK_CLONES is true, also check for clones of ctor/dtors.  */
48410d565efSmrg 
48510d565efSmrg tree
polymorphic_ctor_dtor_p(tree fn,bool check_clones)48610d565efSmrg polymorphic_ctor_dtor_p (tree fn, bool check_clones)
48710d565efSmrg {
48810d565efSmrg   if (TREE_CODE (TREE_TYPE (fn)) != METHOD_TYPE
48910d565efSmrg       || (!DECL_CXX_CONSTRUCTOR_P (fn) && !DECL_CXX_DESTRUCTOR_P (fn)))
49010d565efSmrg     {
49110d565efSmrg       if (!check_clones)
49210d565efSmrg 	return NULL_TREE;
49310d565efSmrg 
49410d565efSmrg       /* Watch for clones where we constant propagated the first
49510d565efSmrg 	 argument (pointer to the instance).  */
49610d565efSmrg       fn = DECL_ABSTRACT_ORIGIN (fn);
49710d565efSmrg       if (!fn
49810d565efSmrg 	  || TREE_CODE (TREE_TYPE (fn)) != METHOD_TYPE
49910d565efSmrg 	  || (!DECL_CXX_CONSTRUCTOR_P (fn) && !DECL_CXX_DESTRUCTOR_P (fn)))
50010d565efSmrg 	return NULL_TREE;
50110d565efSmrg     }
50210d565efSmrg 
50310d565efSmrg   if (flags_from_decl_or_type (fn) & (ECF_PURE | ECF_CONST))
50410d565efSmrg     return NULL_TREE;
50510d565efSmrg 
50610d565efSmrg   return fn;
50710d565efSmrg }
50810d565efSmrg 
50910d565efSmrg /* Return a FUNCTION_DECL if BLOCK represents a constructor or destructor.
51010d565efSmrg    If CHECK_CLONES is true, also check for clones of ctor/dtors.  */
51110d565efSmrg 
51210d565efSmrg tree
inlined_polymorphic_ctor_dtor_block_p(tree block,bool check_clones)51310d565efSmrg inlined_polymorphic_ctor_dtor_block_p (tree block, bool check_clones)
51410d565efSmrg {
51510d565efSmrg   tree fn = block_ultimate_origin (block);
51610d565efSmrg   if (fn == NULL || TREE_CODE (fn) != FUNCTION_DECL)
51710d565efSmrg     return NULL_TREE;
51810d565efSmrg 
51910d565efSmrg   return polymorphic_ctor_dtor_p (fn, check_clones);
52010d565efSmrg }
52110d565efSmrg 
52210d565efSmrg 
52310d565efSmrg /* We know that the instance is stored in variable or parameter
52410d565efSmrg    (not dynamically allocated) and we want to disprove the fact
52510d565efSmrg    that it may be in construction at invocation of CALL.
52610d565efSmrg 
52710d565efSmrg    BASE represents memory location where instance is stored.
52810d565efSmrg    If BASE is NULL, it is assumed to be global memory.
52910d565efSmrg    OUTER_TYPE is known type of the instance or NULL if not
53010d565efSmrg    known.
53110d565efSmrg 
53210d565efSmrg    For the variable to be in construction we actually need to
53310d565efSmrg    be in constructor of corresponding global variable or
53410d565efSmrg    the inline stack of CALL must contain the constructor.
53510d565efSmrg    Check this condition.  This check works safely only before
53610d565efSmrg    IPA passes, because inline stacks may become out of date
53710d565efSmrg    later.  */
53810d565efSmrg 
53910d565efSmrg bool
decl_maybe_in_construction_p(tree base,tree outer_type,gimple * call,tree function)54010d565efSmrg decl_maybe_in_construction_p (tree base, tree outer_type,
54110d565efSmrg 			      gimple *call, tree function)
54210d565efSmrg {
54310d565efSmrg   if (outer_type)
54410d565efSmrg     outer_type = TYPE_MAIN_VARIANT (outer_type);
54510d565efSmrg   gcc_assert (!base || DECL_P (base));
54610d565efSmrg 
54710d565efSmrg   /* After inlining the code unification optimizations may invalidate
54810d565efSmrg      inline stacks.  Also we need to give up on global variables after
54910d565efSmrg      IPA, because addresses of these may have been propagated to their
55010d565efSmrg      constructors.  */
55110d565efSmrg   if (DECL_STRUCT_FUNCTION (function)->after_inlining)
55210d565efSmrg     return true;
55310d565efSmrg 
55410d565efSmrg   /* Pure functions cannot do any changes on the dynamic type;
555*ec02198aSmrg      that require writing to memory.  */
55610d565efSmrg   if ((!base || !auto_var_in_fn_p (base, function))
55710d565efSmrg       && flags_from_decl_or_type (function) & (ECF_PURE | ECF_CONST))
55810d565efSmrg     return false;
55910d565efSmrg 
56010d565efSmrg   bool check_clones = !base || is_global_var (base);
56110d565efSmrg   for (tree block = gimple_block (call); block && TREE_CODE (block) == BLOCK;
56210d565efSmrg        block = BLOCK_SUPERCONTEXT (block))
56310d565efSmrg     if (tree fn = inlined_polymorphic_ctor_dtor_block_p (block, check_clones))
56410d565efSmrg       {
56510d565efSmrg 	tree type = TYPE_METHOD_BASETYPE (TREE_TYPE (fn));
56610d565efSmrg 
56710d565efSmrg 	if (!outer_type || !types_odr_comparable (type, outer_type))
56810d565efSmrg 	  {
56910d565efSmrg 	    if (TREE_CODE (type) == RECORD_TYPE
57010d565efSmrg 		&& TYPE_BINFO (type)
57110d565efSmrg 		&& polymorphic_type_binfo_p (TYPE_BINFO (type)))
57210d565efSmrg 	      return true;
57310d565efSmrg 	  }
57410d565efSmrg  	else if (types_same_for_odr (type, outer_type))
57510d565efSmrg 	  return true;
57610d565efSmrg       }
57710d565efSmrg 
57810d565efSmrg   if (!base || (VAR_P (base) && is_global_var (base)))
57910d565efSmrg     {
58010d565efSmrg       if (TREE_CODE (TREE_TYPE (function)) != METHOD_TYPE
58110d565efSmrg 	  || (!DECL_CXX_CONSTRUCTOR_P (function)
58210d565efSmrg 	      && !DECL_CXX_DESTRUCTOR_P (function)))
58310d565efSmrg 	{
58410d565efSmrg 	  if (!DECL_ABSTRACT_ORIGIN (function))
58510d565efSmrg 	    return false;
58610d565efSmrg 	  /* Watch for clones where we constant propagated the first
58710d565efSmrg 	     argument (pointer to the instance).  */
58810d565efSmrg 	  function = DECL_ABSTRACT_ORIGIN (function);
58910d565efSmrg 	  if (!function
59010d565efSmrg 	      || TREE_CODE (TREE_TYPE (function)) != METHOD_TYPE
59110d565efSmrg 	      || (!DECL_CXX_CONSTRUCTOR_P (function)
59210d565efSmrg 		  && !DECL_CXX_DESTRUCTOR_P (function)))
59310d565efSmrg 	    return false;
59410d565efSmrg 	}
59510d565efSmrg       tree type = TYPE_METHOD_BASETYPE (TREE_TYPE (function));
59610d565efSmrg       if (!outer_type || !types_odr_comparable (type, outer_type))
59710d565efSmrg 	{
59810d565efSmrg 	  if (TREE_CODE (type) == RECORD_TYPE
59910d565efSmrg 	      && TYPE_BINFO (type)
60010d565efSmrg 	      && polymorphic_type_binfo_p (TYPE_BINFO (type)))
60110d565efSmrg 	    return true;
60210d565efSmrg 	}
60310d565efSmrg       else if (types_same_for_odr (type, outer_type))
60410d565efSmrg 	return true;
60510d565efSmrg     }
60610d565efSmrg   return false;
60710d565efSmrg }
60810d565efSmrg 
60910d565efSmrg /* Dump human readable context to F.  If NEWLINE is true, it will be terminated
61010d565efSmrg    by a newline.  */
61110d565efSmrg 
61210d565efSmrg void
dump(FILE * f,bool newline)61310d565efSmrg ipa_polymorphic_call_context::dump (FILE *f, bool newline) const
61410d565efSmrg {
61510d565efSmrg   fprintf (f, "    ");
61610d565efSmrg   if (invalid)
61710d565efSmrg     fprintf (f, "Call is known to be undefined");
61810d565efSmrg   else
61910d565efSmrg     {
62010d565efSmrg       if (useless_p ())
62110d565efSmrg 	fprintf (f, "nothing known");
62210d565efSmrg       if (outer_type || offset)
62310d565efSmrg 	{
62410d565efSmrg 	  fprintf (f, "Outer type%s:", dynamic ? " (dynamic)":"");
62510d565efSmrg 	  print_generic_expr (f, outer_type, TDF_SLIM);
62610d565efSmrg 	  if (maybe_derived_type)
62710d565efSmrg 	    fprintf (f, " (or a derived type)");
62810d565efSmrg 	  if (maybe_in_construction)
62910d565efSmrg 	    fprintf (f, " (maybe in construction)");
63010d565efSmrg 	  fprintf (f, " offset " HOST_WIDE_INT_PRINT_DEC,
63110d565efSmrg 		   offset);
63210d565efSmrg 	}
63310d565efSmrg       if (speculative_outer_type)
63410d565efSmrg 	{
63510d565efSmrg 	  if (outer_type || offset)
63610d565efSmrg 	    fprintf (f, " ");
63710d565efSmrg 	  fprintf (f, "Speculative outer type:");
63810d565efSmrg 	  print_generic_expr (f, speculative_outer_type, TDF_SLIM);
63910d565efSmrg 	  if (speculative_maybe_derived_type)
64010d565efSmrg 	    fprintf (f, " (or a derived type)");
64110d565efSmrg 	  fprintf (f, " at offset " HOST_WIDE_INT_PRINT_DEC,
64210d565efSmrg 		   speculative_offset);
64310d565efSmrg 	}
64410d565efSmrg     }
64510d565efSmrg   if (newline)
64610d565efSmrg     fprintf(f, "\n");
64710d565efSmrg }
64810d565efSmrg 
64910d565efSmrg /* Print context to stderr.  */
65010d565efSmrg 
65110d565efSmrg void
debug()65210d565efSmrg ipa_polymorphic_call_context::debug () const
65310d565efSmrg {
65410d565efSmrg   dump (stderr);
65510d565efSmrg }
65610d565efSmrg 
65710d565efSmrg /* Stream out the context to OB.  */
65810d565efSmrg 
65910d565efSmrg void
stream_out(struct output_block * ob)66010d565efSmrg ipa_polymorphic_call_context::stream_out (struct output_block *ob) const
66110d565efSmrg {
66210d565efSmrg   struct bitpack_d bp = bitpack_create (ob->main_stream);
66310d565efSmrg 
66410d565efSmrg   bp_pack_value (&bp, invalid, 1);
66510d565efSmrg   bp_pack_value (&bp, maybe_in_construction, 1);
66610d565efSmrg   bp_pack_value (&bp, maybe_derived_type, 1);
66710d565efSmrg   bp_pack_value (&bp, speculative_maybe_derived_type, 1);
66810d565efSmrg   bp_pack_value (&bp, dynamic, 1);
66910d565efSmrg   bp_pack_value (&bp, outer_type != NULL, 1);
67010d565efSmrg   bp_pack_value (&bp, offset != 0, 1);
67110d565efSmrg   bp_pack_value (&bp, speculative_outer_type != NULL, 1);
67210d565efSmrg   streamer_write_bitpack (&bp);
67310d565efSmrg 
67410d565efSmrg   if (outer_type != NULL)
67510d565efSmrg     stream_write_tree (ob, outer_type, true);
67610d565efSmrg   if (offset)
67710d565efSmrg     streamer_write_hwi (ob, offset);
67810d565efSmrg   if (speculative_outer_type != NULL)
67910d565efSmrg     {
68010d565efSmrg       stream_write_tree (ob, speculative_outer_type, true);
68110d565efSmrg       streamer_write_hwi (ob, speculative_offset);
68210d565efSmrg     }
68310d565efSmrg   else
68410d565efSmrg     gcc_assert (!speculative_offset);
68510d565efSmrg }
68610d565efSmrg 
68710d565efSmrg /* Stream in the context from IB and DATA_IN.  */
68810d565efSmrg 
68910d565efSmrg void
stream_in(class lto_input_block * ib,class data_in * data_in)690*ec02198aSmrg ipa_polymorphic_call_context::stream_in (class lto_input_block *ib,
691*ec02198aSmrg 					 class data_in *data_in)
69210d565efSmrg {
69310d565efSmrg   struct bitpack_d bp = streamer_read_bitpack (ib);
69410d565efSmrg 
69510d565efSmrg   invalid = bp_unpack_value (&bp, 1);
69610d565efSmrg   maybe_in_construction = bp_unpack_value (&bp, 1);
69710d565efSmrg   maybe_derived_type = bp_unpack_value (&bp, 1);
69810d565efSmrg   speculative_maybe_derived_type = bp_unpack_value (&bp, 1);
69910d565efSmrg   dynamic = bp_unpack_value (&bp, 1);
70010d565efSmrg   bool outer_type_p = bp_unpack_value (&bp, 1);
70110d565efSmrg   bool offset_p = bp_unpack_value (&bp, 1);
70210d565efSmrg   bool speculative_outer_type_p = bp_unpack_value (&bp, 1);
70310d565efSmrg 
70410d565efSmrg   if (outer_type_p)
70510d565efSmrg     outer_type = stream_read_tree (ib, data_in);
70610d565efSmrg   else
70710d565efSmrg     outer_type = NULL;
70810d565efSmrg   if (offset_p)
70910d565efSmrg     offset = (HOST_WIDE_INT) streamer_read_hwi (ib);
71010d565efSmrg   else
71110d565efSmrg     offset = 0;
71210d565efSmrg   if (speculative_outer_type_p)
71310d565efSmrg     {
71410d565efSmrg       speculative_outer_type = stream_read_tree (ib, data_in);
71510d565efSmrg       speculative_offset = (HOST_WIDE_INT) streamer_read_hwi (ib);
71610d565efSmrg     }
71710d565efSmrg   else
71810d565efSmrg     {
71910d565efSmrg       speculative_outer_type = NULL;
72010d565efSmrg       speculative_offset = 0;
72110d565efSmrg     }
72210d565efSmrg }
72310d565efSmrg 
724*ec02198aSmrg /* Produce polymorphic call context for call method of instance
72510d565efSmrg    that is located within BASE (that is assumed to be a decl) at offset OFF. */
72610d565efSmrg 
72710d565efSmrg void
set_by_decl(tree base,HOST_WIDE_INT off)72810d565efSmrg ipa_polymorphic_call_context::set_by_decl (tree base, HOST_WIDE_INT off)
72910d565efSmrg {
73010d565efSmrg   gcc_assert (DECL_P (base));
73110d565efSmrg   clear_speculation ();
73210d565efSmrg 
73310d565efSmrg   if (!contains_polymorphic_type_p (TREE_TYPE (base)))
73410d565efSmrg     {
73510d565efSmrg       clear_outer_type ();
73610d565efSmrg       offset = off;
73710d565efSmrg       return;
73810d565efSmrg     }
73910d565efSmrg   outer_type = TYPE_MAIN_VARIANT (TREE_TYPE (base));
74010d565efSmrg   offset = off;
74110d565efSmrg   /* Make very conservative assumption that all objects
74210d565efSmrg      may be in construction.
74310d565efSmrg 
74410d565efSmrg      It is up to caller to revisit this via
74510d565efSmrg      get_dynamic_type or decl_maybe_in_construction_p.  */
74610d565efSmrg   maybe_in_construction = true;
74710d565efSmrg   maybe_derived_type = false;
74810d565efSmrg   dynamic = false;
74910d565efSmrg }
75010d565efSmrg 
75110d565efSmrg /* CST is an invariant (address of decl), try to get meaningful
75210d565efSmrg    polymorphic call context for polymorphic call of method
75310d565efSmrg    if instance of OTR_TYPE that is located at offset OFF of this invariant.
75410d565efSmrg    Return FALSE if nothing meaningful can be found.  */
75510d565efSmrg 
75610d565efSmrg bool
set_by_invariant(tree cst,tree otr_type,HOST_WIDE_INT off)75710d565efSmrg ipa_polymorphic_call_context::set_by_invariant (tree cst,
75810d565efSmrg 						tree otr_type,
75910d565efSmrg 						HOST_WIDE_INT off)
76010d565efSmrg {
761c7a68eb7Smrg   poly_int64 offset2, size, max_size;
76210d565efSmrg   bool reverse;
76310d565efSmrg   tree base;
76410d565efSmrg 
76510d565efSmrg   invalid = false;
76610d565efSmrg   off = 0;
76710d565efSmrg   clear_outer_type (otr_type);
76810d565efSmrg 
76910d565efSmrg   if (TREE_CODE (cst) != ADDR_EXPR)
77010d565efSmrg     return false;
77110d565efSmrg 
77210d565efSmrg   cst = TREE_OPERAND (cst, 0);
77310d565efSmrg   base = get_ref_base_and_extent (cst, &offset2, &size, &max_size, &reverse);
774c7a68eb7Smrg   if (!DECL_P (base) || !known_size_p (max_size) || maybe_ne (max_size, size))
77510d565efSmrg     return false;
77610d565efSmrg 
77710d565efSmrg   /* Only type inconsistent programs can have otr_type that is
77810d565efSmrg      not part of outer type.  */
77910d565efSmrg   if (otr_type && !contains_type_p (TREE_TYPE (base), off, otr_type))
78010d565efSmrg     return false;
78110d565efSmrg 
78210d565efSmrg   set_by_decl (base, off);
78310d565efSmrg   return true;
78410d565efSmrg }
78510d565efSmrg 
78610d565efSmrg /* See if OP is SSA name initialized as a copy or by single assignment.
78710d565efSmrg    If so, walk the SSA graph up.  Because simple PHI conditional is considered
78810d565efSmrg    copy, GLOBAL_VISITED may be used to avoid infinite loop walking the SSA
78910d565efSmrg    graph.  */
79010d565efSmrg 
79110d565efSmrg static tree
79210d565efSmrg walk_ssa_copies (tree op, hash_set<tree> **global_visited = NULL)
79310d565efSmrg {
79410d565efSmrg   hash_set <tree> *visited = NULL;
79510d565efSmrg   STRIP_NOPS (op);
79610d565efSmrg   while (TREE_CODE (op) == SSA_NAME
79710d565efSmrg 	 && !SSA_NAME_IS_DEFAULT_DEF (op)
79810d565efSmrg 	 /* We might be called via fold_stmt during cfgcleanup where
79910d565efSmrg 	    SSA form need not be up-to-date.  */
80010d565efSmrg 	 && !name_registered_for_update_p (op)
80110d565efSmrg 	 && (gimple_assign_single_p (SSA_NAME_DEF_STMT (op))
80210d565efSmrg 	     || gimple_code (SSA_NAME_DEF_STMT (op)) == GIMPLE_PHI))
80310d565efSmrg     {
80410d565efSmrg       if (global_visited)
80510d565efSmrg 	{
80610d565efSmrg 	  if (!*global_visited)
80710d565efSmrg 	    *global_visited = new hash_set<tree>;
80810d565efSmrg 	  if ((*global_visited)->add (op))
80910d565efSmrg 	    goto done;
81010d565efSmrg 	}
81110d565efSmrg       else
81210d565efSmrg 	{
81310d565efSmrg 	  if (!visited)
81410d565efSmrg 	    visited = new hash_set<tree>;
81510d565efSmrg 	  if (visited->add (op))
81610d565efSmrg 	    goto done;
81710d565efSmrg 	}
81810d565efSmrg       /* Special case
81910d565efSmrg 	 if (ptr == 0)
82010d565efSmrg 	   ptr = 0;
82110d565efSmrg 	 else
82210d565efSmrg 	   ptr = ptr.foo;
82310d565efSmrg 	 This pattern is implicitly produced for casts to non-primary
82410d565efSmrg 	 bases.  When doing context analysis, we do not really care
82510d565efSmrg 	 about the case pointer is NULL, because the call will be
82610d565efSmrg 	 undefined anyway.  */
82710d565efSmrg       if (gimple_code (SSA_NAME_DEF_STMT (op)) == GIMPLE_PHI)
82810d565efSmrg 	{
82910d565efSmrg 	  gimple *phi = SSA_NAME_DEF_STMT (op);
83010d565efSmrg 
83110d565efSmrg 	  if (gimple_phi_num_args (phi) > 2)
83210d565efSmrg 	    goto done;
83310d565efSmrg 	  if (gimple_phi_num_args (phi) == 1)
83410d565efSmrg 	    op = gimple_phi_arg_def (phi, 0);
83510d565efSmrg 	  else if (integer_zerop (gimple_phi_arg_def (phi, 0)))
83610d565efSmrg 	    op = gimple_phi_arg_def (phi, 1);
83710d565efSmrg 	  else if (integer_zerop (gimple_phi_arg_def (phi, 1)))
83810d565efSmrg 	    op = gimple_phi_arg_def (phi, 0);
83910d565efSmrg 	  else
84010d565efSmrg 	    goto done;
84110d565efSmrg 	}
84210d565efSmrg       else
84310d565efSmrg 	{
84410d565efSmrg 	  if (gimple_assign_load_p (SSA_NAME_DEF_STMT (op)))
84510d565efSmrg 	    goto done;
84610d565efSmrg 	  op = gimple_assign_rhs1 (SSA_NAME_DEF_STMT (op));
84710d565efSmrg 	}
84810d565efSmrg       STRIP_NOPS (op);
84910d565efSmrg     }
85010d565efSmrg done:
85110d565efSmrg   if (visited)
85210d565efSmrg     delete (visited);
85310d565efSmrg   return op;
85410d565efSmrg }
85510d565efSmrg 
85610d565efSmrg /* Create polymorphic call context from IP invariant CST.
85710d565efSmrg    This is typically &global_var.
85810d565efSmrg    OTR_TYPE specify type of polymorphic call or NULL if unknown, OFF
85910d565efSmrg    is offset of call.  */
86010d565efSmrg 
ipa_polymorphic_call_context(tree cst,tree otr_type,HOST_WIDE_INT off)86110d565efSmrg ipa_polymorphic_call_context::ipa_polymorphic_call_context (tree cst,
86210d565efSmrg 							    tree otr_type,
86310d565efSmrg 							    HOST_WIDE_INT off)
86410d565efSmrg {
86510d565efSmrg   clear_speculation ();
86610d565efSmrg   set_by_invariant (cst, otr_type, off);
86710d565efSmrg }
86810d565efSmrg 
86910d565efSmrg /* Build context for pointer REF contained in FNDECL at statement STMT.
87010d565efSmrg    if INSTANCE is non-NULL, return pointer to the object described by
87110d565efSmrg    the context or DECL where context is contained in.  */
87210d565efSmrg 
ipa_polymorphic_call_context(tree fndecl,tree ref,gimple * stmt,tree * instance)87310d565efSmrg ipa_polymorphic_call_context::ipa_polymorphic_call_context (tree fndecl,
87410d565efSmrg 							    tree ref,
87510d565efSmrg 							    gimple *stmt,
87610d565efSmrg 							    tree *instance)
87710d565efSmrg {
87810d565efSmrg   tree otr_type = NULL;
87910d565efSmrg   tree base_pointer;
88010d565efSmrg   hash_set <tree> *visited = NULL;
88110d565efSmrg 
88210d565efSmrg   if (TREE_CODE (ref) == OBJ_TYPE_REF)
88310d565efSmrg     {
88410d565efSmrg       otr_type = obj_type_ref_class (ref);
88510d565efSmrg       base_pointer = OBJ_TYPE_REF_OBJECT (ref);
88610d565efSmrg     }
88710d565efSmrg   else
88810d565efSmrg     base_pointer = ref;
88910d565efSmrg 
89010d565efSmrg   /* Set up basic info in case we find nothing interesting in the analysis.  */
89110d565efSmrg   clear_speculation ();
89210d565efSmrg   clear_outer_type (otr_type);
89310d565efSmrg   invalid = false;
89410d565efSmrg 
89510d565efSmrg   /* Walk SSA for outer object.  */
89610d565efSmrg   while (true)
89710d565efSmrg     {
89810d565efSmrg       base_pointer = walk_ssa_copies (base_pointer, &visited);
89910d565efSmrg       if (TREE_CODE (base_pointer) == ADDR_EXPR)
90010d565efSmrg 	{
901c7a68eb7Smrg 	  HOST_WIDE_INT offset2, size;
90210d565efSmrg 	  bool reverse;
90310d565efSmrg 	  tree base
904c7a68eb7Smrg 	    = get_ref_base_and_extent_hwi (TREE_OPERAND (base_pointer, 0),
905c7a68eb7Smrg 					   &offset2, &size, &reverse);
906c7a68eb7Smrg 	  if (!base)
907c7a68eb7Smrg 	    break;
90810d565efSmrg 
90910d565efSmrg 	  combine_speculation_with (TYPE_MAIN_VARIANT (TREE_TYPE (base)),
91010d565efSmrg 				    offset + offset2,
91110d565efSmrg 				    true,
91210d565efSmrg 				    NULL /* Do not change outer type.  */);
91310d565efSmrg 
91410d565efSmrg 	  /* If this is a varying address, punt.  */
915c7a68eb7Smrg 	  if (TREE_CODE (base) == MEM_REF || DECL_P (base))
91610d565efSmrg 	    {
91710d565efSmrg 	      /* We found dereference of a pointer.  Type of the pointer
918*ec02198aSmrg 		 and MEM_REF is meaningless, but we can look further.  */
919c7a68eb7Smrg 	      offset_int mem_offset;
920c7a68eb7Smrg 	      if (TREE_CODE (base) == MEM_REF
921c7a68eb7Smrg 		  && mem_ref_offset (base).is_constant (&mem_offset))
92210d565efSmrg 		{
923c7a68eb7Smrg 		  offset_int o = mem_offset * BITS_PER_UNIT;
924c7a68eb7Smrg 		  o += offset;
925c7a68eb7Smrg 		  o += offset2;
926c7a68eb7Smrg 		  if (!wi::fits_shwi_p (o))
927c7a68eb7Smrg 		    break;
92810d565efSmrg 		  base_pointer = TREE_OPERAND (base, 0);
929c7a68eb7Smrg 		  offset = o.to_shwi ();
93010d565efSmrg 		  outer_type = NULL;
93110d565efSmrg 		}
93210d565efSmrg 	      /* We found base object.  In this case the outer_type
93310d565efSmrg 		 is known.  */
93410d565efSmrg 	      else if (DECL_P (base))
93510d565efSmrg 		{
93610d565efSmrg 		  if (visited)
93710d565efSmrg 		    delete (visited);
93810d565efSmrg 		  /* Only type inconsistent programs can have otr_type that is
93910d565efSmrg 		     not part of outer type.  */
94010d565efSmrg 		  if (otr_type
94110d565efSmrg 		      && !contains_type_p (TREE_TYPE (base),
94210d565efSmrg 					   offset + offset2, otr_type))
94310d565efSmrg 		    {
94410d565efSmrg 		      invalid = true;
94510d565efSmrg 		      if (instance)
94610d565efSmrg 			*instance = base_pointer;
94710d565efSmrg 		      return;
94810d565efSmrg 		    }
94910d565efSmrg 		  set_by_decl (base, offset + offset2);
95010d565efSmrg 		  if (outer_type && maybe_in_construction && stmt)
95110d565efSmrg 		    maybe_in_construction
95210d565efSmrg 		     = decl_maybe_in_construction_p (base,
95310d565efSmrg 						     outer_type,
95410d565efSmrg 						     stmt,
95510d565efSmrg 						     fndecl);
95610d565efSmrg 		  if (instance)
95710d565efSmrg 		    *instance = base;
95810d565efSmrg 		  return;
95910d565efSmrg 		}
96010d565efSmrg 	      else
96110d565efSmrg 		break;
96210d565efSmrg 	    }
96310d565efSmrg 	  else
96410d565efSmrg 	    break;
96510d565efSmrg 	}
96610d565efSmrg       else if (TREE_CODE (base_pointer) == POINTER_PLUS_EXPR
967c7a68eb7Smrg 	       && TREE_CODE (TREE_OPERAND (base_pointer, 1)) == INTEGER_CST)
96810d565efSmrg 	{
969c7a68eb7Smrg 	  offset_int o
970c7a68eb7Smrg 	    = offset_int::from (wi::to_wide (TREE_OPERAND (base_pointer, 1)),
971c7a68eb7Smrg 				SIGNED);
972c7a68eb7Smrg 	  o *= BITS_PER_UNIT;
973c7a68eb7Smrg 	  o += offset;
974c7a68eb7Smrg 	  if (!wi::fits_shwi_p (o))
975c7a68eb7Smrg 	    break;
976c7a68eb7Smrg 	  offset = o.to_shwi ();
97710d565efSmrg 	  base_pointer = TREE_OPERAND (base_pointer, 0);
97810d565efSmrg 	}
97910d565efSmrg       else
98010d565efSmrg 	break;
98110d565efSmrg     }
98210d565efSmrg 
98310d565efSmrg   if (visited)
98410d565efSmrg     delete (visited);
98510d565efSmrg 
98610d565efSmrg   /* Try to determine type of the outer object.  */
98710d565efSmrg   if (TREE_CODE (base_pointer) == SSA_NAME
98810d565efSmrg       && SSA_NAME_IS_DEFAULT_DEF (base_pointer)
98910d565efSmrg       && TREE_CODE (SSA_NAME_VAR (base_pointer)) == PARM_DECL)
99010d565efSmrg     {
99110d565efSmrg       /* See if parameter is THIS pointer of a method.  */
99210d565efSmrg       if (TREE_CODE (TREE_TYPE (fndecl)) == METHOD_TYPE
99310d565efSmrg 	  && SSA_NAME_VAR (base_pointer) == DECL_ARGUMENTS (fndecl))
99410d565efSmrg 	{
99510d565efSmrg 	  outer_type
99610d565efSmrg 	     = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (base_pointer)));
997c7a68eb7Smrg 	  cgraph_node *node = cgraph_node::get (current_function_decl);
99810d565efSmrg 	  gcc_assert (TREE_CODE (outer_type) == RECORD_TYPE
99910d565efSmrg 		      || TREE_CODE (outer_type) == UNION_TYPE);
100010d565efSmrg 
1001c7a68eb7Smrg 	  /* Handle the case we inlined into a thunk.  In this case
1002c7a68eb7Smrg 	     thunk has THIS pointer of type bar, but it really receives
1003c7a68eb7Smrg 	     address to its base type foo which sits in bar at
1004c7a68eb7Smrg 	     0-thunk.fixed_offset.  It starts with code that adds
1005c7a68eb7Smrg 	     think.fixed_offset to the pointer to compensate for this.
1006c7a68eb7Smrg 
1007*ec02198aSmrg 	     Because we walked all the way to the beginning of thunk, we now
1008c7a68eb7Smrg 	     see pointer &bar-thunk.fixed_offset and need to compensate
1009c7a68eb7Smrg 	     for it.  */
1010c7a68eb7Smrg 	  if (node->thunk.fixed_offset)
1011c7a68eb7Smrg 	    offset -= node->thunk.fixed_offset * BITS_PER_UNIT;
1012c7a68eb7Smrg 
101310d565efSmrg 	  /* Dynamic casting has possibly upcasted the type
1014*ec02198aSmrg 	     in the hierarchy.  In this case outer type is less
101510d565efSmrg 	     informative than inner type and we should forget
101610d565efSmrg 	     about it.  */
101710d565efSmrg 	  if ((otr_type
101810d565efSmrg 	       && !contains_type_p (outer_type, offset,
101910d565efSmrg 				    otr_type))
1020c7a68eb7Smrg 	      || !contains_polymorphic_type_p (outer_type)
1021c7a68eb7Smrg 	      /* If we compile thunk with virtual offset, the THIS pointer
1022c7a68eb7Smrg 		 is adjusted by unknown value.  We can't thus use outer info
1023c7a68eb7Smrg 		 at all.  */
1024c7a68eb7Smrg 	      || node->thunk.virtual_offset_p)
102510d565efSmrg 	    {
102610d565efSmrg 	      outer_type = NULL;
102710d565efSmrg 	      if (instance)
102810d565efSmrg 		*instance = base_pointer;
102910d565efSmrg 	      return;
103010d565efSmrg 	    }
103110d565efSmrg 
103210d565efSmrg 	  dynamic = true;
103310d565efSmrg 
103410d565efSmrg 	  /* If the function is constructor or destructor, then
103510d565efSmrg 	     the type is possibly in construction, but we know
103610d565efSmrg 	     it is not derived type.  */
103710d565efSmrg 	  if (DECL_CXX_CONSTRUCTOR_P (fndecl)
103810d565efSmrg 	      || DECL_CXX_DESTRUCTOR_P (fndecl))
103910d565efSmrg 	    {
104010d565efSmrg 	      maybe_in_construction = true;
104110d565efSmrg 	      maybe_derived_type = false;
104210d565efSmrg 	    }
104310d565efSmrg 	  else
104410d565efSmrg 	    {
104510d565efSmrg 	      maybe_derived_type = true;
104610d565efSmrg 	      maybe_in_construction = false;
104710d565efSmrg 	    }
104810d565efSmrg 	  if (instance)
1049c7a68eb7Smrg 	    {
1050c7a68eb7Smrg 	      /* If method is expanded thunk, we need to apply thunk offset
1051c7a68eb7Smrg 		 to instance pointer.  */
1052c7a68eb7Smrg 	      if (node->thunk.virtual_offset_p
1053c7a68eb7Smrg 		  || node->thunk.fixed_offset)
1054c7a68eb7Smrg 		*instance = NULL;
1055c7a68eb7Smrg 	      else
105610d565efSmrg 	        *instance = base_pointer;
1057c7a68eb7Smrg 	    }
105810d565efSmrg 	  return;
105910d565efSmrg 	}
106010d565efSmrg       /* Non-PODs passed by value are really passed by invisible
106110d565efSmrg 	 reference.  In this case we also know the type of the
106210d565efSmrg 	 object.  */
106310d565efSmrg       if (DECL_BY_REFERENCE (SSA_NAME_VAR (base_pointer)))
106410d565efSmrg 	{
106510d565efSmrg 	  outer_type
106610d565efSmrg 	     = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (base_pointer)));
106710d565efSmrg 	  /* Only type inconsistent programs can have otr_type that is
106810d565efSmrg 	     not part of outer type.  */
106910d565efSmrg 	  if (otr_type && !contains_type_p (outer_type, offset,
107010d565efSmrg 					    otr_type))
107110d565efSmrg 	    {
107210d565efSmrg 	      invalid = true;
107310d565efSmrg 	      if (instance)
107410d565efSmrg 		*instance = base_pointer;
107510d565efSmrg 	      return;
107610d565efSmrg 	    }
107710d565efSmrg 	  /* Non-polymorphic types have no interest for us.  */
107810d565efSmrg 	  else if (!otr_type && !contains_polymorphic_type_p (outer_type))
107910d565efSmrg 	    {
108010d565efSmrg 	      outer_type = NULL;
108110d565efSmrg 	      if (instance)
108210d565efSmrg 		*instance = base_pointer;
108310d565efSmrg 	      return;
108410d565efSmrg 	    }
108510d565efSmrg 	  maybe_derived_type = false;
108610d565efSmrg 	  maybe_in_construction = false;
108710d565efSmrg 	  if (instance)
108810d565efSmrg 	    *instance = base_pointer;
108910d565efSmrg 	  return;
109010d565efSmrg 	}
109110d565efSmrg     }
109210d565efSmrg 
109310d565efSmrg   tree base_type = TREE_TYPE (base_pointer);
109410d565efSmrg 
109510d565efSmrg   if (TREE_CODE (base_pointer) == SSA_NAME
109610d565efSmrg       && SSA_NAME_IS_DEFAULT_DEF (base_pointer)
109710d565efSmrg       && !(TREE_CODE (SSA_NAME_VAR (base_pointer)) == PARM_DECL
109810d565efSmrg 	   || TREE_CODE (SSA_NAME_VAR (base_pointer)) == RESULT_DECL))
109910d565efSmrg     {
110010d565efSmrg       invalid = true;
110110d565efSmrg       if (instance)
110210d565efSmrg 	*instance = base_pointer;
110310d565efSmrg       return;
110410d565efSmrg     }
110510d565efSmrg   if (TREE_CODE (base_pointer) == SSA_NAME
110610d565efSmrg       && SSA_NAME_DEF_STMT (base_pointer)
110710d565efSmrg       && gimple_assign_single_p (SSA_NAME_DEF_STMT (base_pointer)))
110810d565efSmrg     base_type = TREE_TYPE (gimple_assign_rhs1
110910d565efSmrg 			    (SSA_NAME_DEF_STMT (base_pointer)));
111010d565efSmrg 
111110d565efSmrg   if (base_type && POINTER_TYPE_P (base_type))
111210d565efSmrg     combine_speculation_with (TYPE_MAIN_VARIANT (TREE_TYPE (base_type)),
111310d565efSmrg 			      offset,
111410d565efSmrg 			      true, NULL /* Do not change type here */);
111510d565efSmrg   /* TODO: There are multiple ways to derive a type.  For instance
1116*ec02198aSmrg      if BASE_POINTER is passed to an constructor call prior our reference.
111710d565efSmrg      We do not make this type of flow sensitive analysis yet.  */
111810d565efSmrg   if (instance)
111910d565efSmrg     *instance = base_pointer;
112010d565efSmrg   return;
112110d565efSmrg }
112210d565efSmrg 
112310d565efSmrg /* Structure to be passed in between detect_type_change and
112410d565efSmrg    check_stmt_for_type_change.  */
112510d565efSmrg 
112610d565efSmrg struct type_change_info
112710d565efSmrg {
112810d565efSmrg   /* Offset into the object where there is the virtual method pointer we are
112910d565efSmrg      looking for.  */
113010d565efSmrg   HOST_WIDE_INT offset;
113110d565efSmrg   /* The declaration or SSA_NAME pointer of the base that we are checking for
113210d565efSmrg      type change.  */
113310d565efSmrg   tree instance;
113410d565efSmrg   /* The reference to virtual table pointer used.  */
113510d565efSmrg   tree vtbl_ptr_ref;
113610d565efSmrg   tree otr_type;
113710d565efSmrg   /* If we actually can tell the type that the object has changed to, it is
113810d565efSmrg      stored in this field.  Otherwise it remains NULL_TREE.  */
113910d565efSmrg   tree known_current_type;
114010d565efSmrg   HOST_WIDE_INT known_current_offset;
114110d565efSmrg 
114210d565efSmrg   /* Set to nonzero if we possibly missed some dynamic type changes and we
114310d565efSmrg      should consider the set to be speculative.  */
114410d565efSmrg   unsigned speculative;
114510d565efSmrg 
114610d565efSmrg   /* Set to true if dynamic type change has been detected.  */
114710d565efSmrg   bool type_maybe_changed;
114810d565efSmrg   /* Set to true if multiple types have been encountered.  known_current_type
114910d565efSmrg      must be disregarded in that case.  */
115010d565efSmrg   bool multiple_types_encountered;
115110d565efSmrg   bool seen_unanalyzed_store;
115210d565efSmrg };
115310d565efSmrg 
115410d565efSmrg /* Return true if STMT is not call and can modify a virtual method table pointer.
115510d565efSmrg    We take advantage of fact that vtable stores must appear within constructor
115610d565efSmrg    and destructor functions.  */
115710d565efSmrg 
115810d565efSmrg static bool
noncall_stmt_may_be_vtbl_ptr_store(gimple * stmt)115910d565efSmrg noncall_stmt_may_be_vtbl_ptr_store (gimple *stmt)
116010d565efSmrg {
116110d565efSmrg   if (is_gimple_assign (stmt))
116210d565efSmrg     {
116310d565efSmrg       tree lhs = gimple_assign_lhs (stmt);
116410d565efSmrg 
116510d565efSmrg       if (gimple_clobber_p (stmt))
116610d565efSmrg 	return false;
116710d565efSmrg       if (!AGGREGATE_TYPE_P (TREE_TYPE (lhs)))
116810d565efSmrg 	{
116910d565efSmrg 	  if (flag_strict_aliasing
117010d565efSmrg 	      && !POINTER_TYPE_P (TREE_TYPE (lhs)))
117110d565efSmrg 	    return false;
117210d565efSmrg 
117310d565efSmrg 	  if (TREE_CODE (lhs) == COMPONENT_REF
117410d565efSmrg 	      && !DECL_VIRTUAL_P (TREE_OPERAND (lhs, 1)))
117510d565efSmrg 	    return false;
1176c7a68eb7Smrg 	  /* In the future we might want to use get_ref_base_and_extent to find
117710d565efSmrg 	     if there is a field corresponding to the offset and if so, proceed
117810d565efSmrg 	     almost like if it was a component ref.  */
117910d565efSmrg 	}
118010d565efSmrg     }
118110d565efSmrg 
118210d565efSmrg   /* Code unification may mess with inline stacks.  */
118310d565efSmrg   if (cfun->after_inlining)
118410d565efSmrg     return true;
118510d565efSmrg 
118610d565efSmrg   /* Walk the inline stack and watch out for ctors/dtors.
118710d565efSmrg      TODO: Maybe we can require the store to appear in toplevel
118810d565efSmrg      block of CTOR/DTOR.  */
118910d565efSmrg   for (tree block = gimple_block (stmt); block && TREE_CODE (block) == BLOCK;
119010d565efSmrg        block = BLOCK_SUPERCONTEXT (block))
119110d565efSmrg     if (BLOCK_ABSTRACT_ORIGIN (block)
119210d565efSmrg 	&& TREE_CODE (block_ultimate_origin (block)) == FUNCTION_DECL)
119310d565efSmrg       return inlined_polymorphic_ctor_dtor_block_p (block, false);
119410d565efSmrg   return (TREE_CODE (TREE_TYPE (current_function_decl)) == METHOD_TYPE
119510d565efSmrg 	  && (DECL_CXX_CONSTRUCTOR_P (current_function_decl)
119610d565efSmrg 	      || DECL_CXX_DESTRUCTOR_P (current_function_decl)));
119710d565efSmrg }
119810d565efSmrg 
119910d565efSmrg /* If STMT can be proved to be an assignment to the virtual method table
120010d565efSmrg    pointer of ANALYZED_OBJ and the type associated with the new table
120110d565efSmrg    identified, return the type.  Otherwise return NULL_TREE if type changes
120210d565efSmrg    in unknown way or ERROR_MARK_NODE if type is unchanged.  */
120310d565efSmrg 
120410d565efSmrg static tree
extr_type_from_vtbl_ptr_store(gimple * stmt,struct type_change_info * tci,HOST_WIDE_INT * type_offset)120510d565efSmrg extr_type_from_vtbl_ptr_store (gimple *stmt, struct type_change_info *tci,
120610d565efSmrg 			       HOST_WIDE_INT *type_offset)
120710d565efSmrg {
1208c7a68eb7Smrg   poly_int64 offset, size, max_size;
120910d565efSmrg   tree lhs, rhs, base;
121010d565efSmrg   bool reverse;
121110d565efSmrg 
121210d565efSmrg   if (!gimple_assign_single_p (stmt))
121310d565efSmrg     return NULL_TREE;
121410d565efSmrg 
121510d565efSmrg   lhs = gimple_assign_lhs (stmt);
121610d565efSmrg   rhs = gimple_assign_rhs1 (stmt);
121710d565efSmrg   if (TREE_CODE (lhs) != COMPONENT_REF
121810d565efSmrg       || !DECL_VIRTUAL_P (TREE_OPERAND (lhs, 1)))
121910d565efSmrg      {
122010d565efSmrg 	if (dump_file)
122110d565efSmrg 	  fprintf (dump_file, "  LHS is not virtual table.\n");
122210d565efSmrg 	return NULL_TREE;
122310d565efSmrg      }
122410d565efSmrg 
122510d565efSmrg   if (tci->vtbl_ptr_ref && operand_equal_p (lhs, tci->vtbl_ptr_ref, 0))
122610d565efSmrg     ;
122710d565efSmrg   else
122810d565efSmrg     {
122910d565efSmrg       base = get_ref_base_and_extent (lhs, &offset, &size, &max_size, &reverse);
123010d565efSmrg       if (DECL_P (tci->instance))
123110d565efSmrg 	{
123210d565efSmrg 	  if (base != tci->instance)
123310d565efSmrg 	    {
123410d565efSmrg 	      if (dump_file)
123510d565efSmrg 		{
123610d565efSmrg 		  fprintf (dump_file, "    base:");
123710d565efSmrg 		  print_generic_expr (dump_file, base, TDF_SLIM);
123810d565efSmrg 		  fprintf (dump_file, " does not match instance:");
123910d565efSmrg 		  print_generic_expr (dump_file, tci->instance, TDF_SLIM);
124010d565efSmrg 		  fprintf (dump_file, "\n");
124110d565efSmrg 		}
124210d565efSmrg 	      return NULL_TREE;
124310d565efSmrg 	    }
124410d565efSmrg 	}
124510d565efSmrg       else if (TREE_CODE (base) == MEM_REF)
124610d565efSmrg 	{
124710d565efSmrg 	  if (!operand_equal_p (tci->instance, TREE_OPERAND (base, 0), 0))
124810d565efSmrg 	    {
124910d565efSmrg 	      if (dump_file)
125010d565efSmrg 		{
125110d565efSmrg 		  fprintf (dump_file, "    base mem ref:");
125210d565efSmrg 		  print_generic_expr (dump_file, base, TDF_SLIM);
125310d565efSmrg 		  fprintf (dump_file, " does not match instance:");
125410d565efSmrg 		  print_generic_expr (dump_file, tci->instance, TDF_SLIM);
125510d565efSmrg 		  fprintf (dump_file, "\n");
125610d565efSmrg 		}
125710d565efSmrg 	      return NULL_TREE;
125810d565efSmrg 	    }
125910d565efSmrg 	  if (!integer_zerop (TREE_OPERAND (base, 1)))
126010d565efSmrg 	    {
126110d565efSmrg 	      if (!tree_fits_shwi_p (TREE_OPERAND (base, 1)))
126210d565efSmrg 		{
126310d565efSmrg 		  if (dump_file)
126410d565efSmrg 		    {
126510d565efSmrg 		      fprintf (dump_file, "    base mem ref:");
126610d565efSmrg 		      print_generic_expr (dump_file, base, TDF_SLIM);
126710d565efSmrg 		      fprintf (dump_file, " has non-representable offset:");
126810d565efSmrg 		      print_generic_expr (dump_file, tci->instance, TDF_SLIM);
126910d565efSmrg 		      fprintf (dump_file, "\n");
127010d565efSmrg 		    }
127110d565efSmrg 		  return NULL_TREE;
127210d565efSmrg 		}
127310d565efSmrg 	      else
127410d565efSmrg 	        offset += tree_to_shwi (TREE_OPERAND (base, 1)) * BITS_PER_UNIT;
127510d565efSmrg 	    }
127610d565efSmrg 	}
127710d565efSmrg       else if (!operand_equal_p (tci->instance, base, 0)
127810d565efSmrg 	       || tci->offset)
127910d565efSmrg 	{
128010d565efSmrg 	  if (dump_file)
128110d565efSmrg 	    {
128210d565efSmrg 	      fprintf (dump_file, "    base:");
128310d565efSmrg 	      print_generic_expr (dump_file, base, TDF_SLIM);
128410d565efSmrg 	      fprintf (dump_file, " does not match instance:");
128510d565efSmrg 	      print_generic_expr (dump_file, tci->instance, TDF_SLIM);
128610d565efSmrg 	      fprintf (dump_file, " with offset %i\n", (int)tci->offset);
128710d565efSmrg 	    }
128810d565efSmrg 	  return tci->offset > POINTER_SIZE ? error_mark_node : NULL_TREE;
128910d565efSmrg 	}
1290c7a68eb7Smrg       if (maybe_ne (offset, tci->offset)
1291c7a68eb7Smrg 	  || maybe_ne (size, POINTER_SIZE)
1292c7a68eb7Smrg 	  || maybe_ne (max_size, POINTER_SIZE))
129310d565efSmrg 	{
129410d565efSmrg 	  if (dump_file)
1295c7a68eb7Smrg 	    {
1296c7a68eb7Smrg 	      fprintf (dump_file, "    wrong offset ");
1297c7a68eb7Smrg 	      print_dec (offset, dump_file);
1298c7a68eb7Smrg 	      fprintf (dump_file, "!=%i or size ", (int) tci->offset);
1299c7a68eb7Smrg 	      print_dec (size, dump_file);
1300c7a68eb7Smrg 	      fprintf (dump_file, "\n");
1301c7a68eb7Smrg 	    }
1302c7a68eb7Smrg 	  return (known_le (offset + POINTER_SIZE, tci->offset)
1303c7a68eb7Smrg 		  || (known_size_p (max_size)
1304c7a68eb7Smrg 		      && known_gt (tci->offset + POINTER_SIZE,
1305c7a68eb7Smrg 				   offset + max_size))
1306c7a68eb7Smrg 		  ? error_mark_node : NULL);
130710d565efSmrg 	}
130810d565efSmrg     }
130910d565efSmrg 
131010d565efSmrg   tree vtable;
131110d565efSmrg   unsigned HOST_WIDE_INT offset2;
131210d565efSmrg 
131310d565efSmrg   if (!vtable_pointer_value_to_vtable (rhs, &vtable, &offset2))
131410d565efSmrg     {
131510d565efSmrg       if (dump_file)
131610d565efSmrg 	fprintf (dump_file, "    Failed to lookup binfo\n");
131710d565efSmrg       return NULL;
131810d565efSmrg     }
131910d565efSmrg 
132010d565efSmrg   tree binfo = subbinfo_with_vtable_at_offset (TYPE_BINFO (DECL_CONTEXT (vtable)),
132110d565efSmrg 					       offset2, vtable);
132210d565efSmrg   if (!binfo)
132310d565efSmrg     {
132410d565efSmrg       if (dump_file)
132510d565efSmrg 	fprintf (dump_file, "    Construction vtable used\n");
1326*ec02198aSmrg       /* FIXME: We should support construction contexts.  */
132710d565efSmrg       return NULL;
132810d565efSmrg     }
132910d565efSmrg 
133010d565efSmrg   *type_offset = tree_to_shwi (BINFO_OFFSET (binfo)) * BITS_PER_UNIT;
133110d565efSmrg   return DECL_CONTEXT (vtable);
133210d565efSmrg }
133310d565efSmrg 
133410d565efSmrg /* Record dynamic type change of TCI to TYPE.  */
133510d565efSmrg 
133610d565efSmrg static void
record_known_type(struct type_change_info * tci,tree type,HOST_WIDE_INT offset)133710d565efSmrg record_known_type (struct type_change_info *tci, tree type, HOST_WIDE_INT offset)
133810d565efSmrg {
133910d565efSmrg   if (dump_file)
134010d565efSmrg     {
134110d565efSmrg       if (type)
134210d565efSmrg 	{
134310d565efSmrg           fprintf (dump_file, "  Recording type: ");
134410d565efSmrg 	  print_generic_expr (dump_file, type, TDF_SLIM);
134510d565efSmrg           fprintf (dump_file, " at offset %i\n", (int)offset);
134610d565efSmrg 	}
134710d565efSmrg      else
134810d565efSmrg        fprintf (dump_file, "  Recording unknown type\n");
134910d565efSmrg     }
135010d565efSmrg 
135110d565efSmrg   /* If we found a constructor of type that is not polymorphic or
135210d565efSmrg      that may contain the type in question as a field (not as base),
135310d565efSmrg      restrict to the inner class first to make type matching bellow
135410d565efSmrg      happier.  */
135510d565efSmrg   if (type
135610d565efSmrg       && (offset
135710d565efSmrg           || (TREE_CODE (type) != RECORD_TYPE
135810d565efSmrg 	      || !TYPE_BINFO (type)
135910d565efSmrg 	      || !polymorphic_type_binfo_p (TYPE_BINFO (type)))))
136010d565efSmrg     {
136110d565efSmrg       ipa_polymorphic_call_context context;
136210d565efSmrg 
136310d565efSmrg       context.offset = offset;
136410d565efSmrg       context.outer_type = type;
136510d565efSmrg       context.maybe_in_construction = false;
136610d565efSmrg       context.maybe_derived_type = false;
136710d565efSmrg       context.dynamic = true;
136810d565efSmrg       /* If we failed to find the inner type, we know that the call
136910d565efSmrg 	 would be undefined for type produced here.  */
137010d565efSmrg       if (!context.restrict_to_inner_class (tci->otr_type))
137110d565efSmrg 	{
137210d565efSmrg 	  if (dump_file)
137310d565efSmrg 	    fprintf (dump_file, "  Ignoring; does not contain otr_type\n");
137410d565efSmrg 	  return;
137510d565efSmrg 	}
137610d565efSmrg       /* Watch for case we reached an POD type and anticipate placement
137710d565efSmrg 	 new.  */
137810d565efSmrg       if (!context.maybe_derived_type)
137910d565efSmrg 	{
138010d565efSmrg           type = context.outer_type;
138110d565efSmrg           offset = context.offset;
138210d565efSmrg 	}
138310d565efSmrg     }
138410d565efSmrg   if (tci->type_maybe_changed
138510d565efSmrg       && (!types_same_for_odr (type, tci->known_current_type)
138610d565efSmrg 	  || offset != tci->known_current_offset))
138710d565efSmrg     tci->multiple_types_encountered = true;
138810d565efSmrg   tci->known_current_type = TYPE_MAIN_VARIANT (type);
138910d565efSmrg   tci->known_current_offset = offset;
139010d565efSmrg   tci->type_maybe_changed = true;
139110d565efSmrg }
139210d565efSmrg 
139310d565efSmrg 
139410d565efSmrg /* The maximum number of may-defs we visit when looking for a must-def
139510d565efSmrg    that changes the dynamic type in check_stmt_for_type_change.  Tuned
139610d565efSmrg    after the PR12392 testcase which unlimited spends 40% time within
139710d565efSmrg    these alias walks and 8% with the following limit.  */
139810d565efSmrg 
139910d565efSmrg static inline bool
csftc_abort_walking_p(unsigned speculative)140010d565efSmrg csftc_abort_walking_p (unsigned speculative)
140110d565efSmrg {
1402*ec02198aSmrg   unsigned max = param_max_speculative_devirt_maydefs;
140310d565efSmrg   return speculative > max ? true : false;
140410d565efSmrg }
140510d565efSmrg 
140610d565efSmrg /* Callback of walk_aliased_vdefs and a helper function for
140710d565efSmrg    detect_type_change to check whether a particular statement may modify
140810d565efSmrg    the virtual table pointer, and if possible also determine the new type of
140910d565efSmrg    the (sub-)object.  It stores its result into DATA, which points to a
141010d565efSmrg    type_change_info structure.  */
141110d565efSmrg 
141210d565efSmrg static bool
check_stmt_for_type_change(ao_ref * ao ATTRIBUTE_UNUSED,tree vdef,void * data)141310d565efSmrg check_stmt_for_type_change (ao_ref *ao ATTRIBUTE_UNUSED, tree vdef, void *data)
141410d565efSmrg {
141510d565efSmrg   gimple *stmt = SSA_NAME_DEF_STMT (vdef);
141610d565efSmrg   struct type_change_info *tci = (struct type_change_info *) data;
141710d565efSmrg   tree fn;
141810d565efSmrg 
141910d565efSmrg   /* If we already gave up, just terminate the rest of walk.  */
142010d565efSmrg   if (tci->multiple_types_encountered)
142110d565efSmrg     return true;
142210d565efSmrg 
142310d565efSmrg   if (is_gimple_call (stmt))
142410d565efSmrg     {
142510d565efSmrg       if (gimple_call_flags (stmt) & (ECF_CONST | ECF_PURE))
142610d565efSmrg 	return false;
142710d565efSmrg 
142810d565efSmrg       /* Check for a constructor call.  */
142910d565efSmrg       if ((fn = gimple_call_fndecl (stmt)) != NULL_TREE
143010d565efSmrg 	  && DECL_CXX_CONSTRUCTOR_P (fn)
143110d565efSmrg 	  && TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE
143210d565efSmrg 	  && gimple_call_num_args (stmt))
143310d565efSmrg       {
143410d565efSmrg 	tree op = walk_ssa_copies (gimple_call_arg (stmt, 0));
143510d565efSmrg 	tree type = TYPE_METHOD_BASETYPE (TREE_TYPE (fn));
1436c7a68eb7Smrg 	HOST_WIDE_INT offset = 0;
143710d565efSmrg 	bool reverse;
143810d565efSmrg 
143910d565efSmrg 	if (dump_file)
144010d565efSmrg 	  {
144110d565efSmrg 	    fprintf (dump_file, "  Checking constructor call: ");
1442c7a68eb7Smrg 	    print_gimple_stmt (dump_file, stmt, 0);
144310d565efSmrg 	  }
144410d565efSmrg 
144510d565efSmrg 	/* See if THIS parameter seems like instance pointer.  */
144610d565efSmrg 	if (TREE_CODE (op) == ADDR_EXPR)
144710d565efSmrg 	  {
1448c7a68eb7Smrg 	    HOST_WIDE_INT size;
1449c7a68eb7Smrg 	    op = get_ref_base_and_extent_hwi (TREE_OPERAND (op, 0),
1450c7a68eb7Smrg 					      &offset, &size, &reverse);
1451c7a68eb7Smrg 	    if (!op)
145210d565efSmrg 	      {
145310d565efSmrg                 tci->speculative++;
145410d565efSmrg 	        return csftc_abort_walking_p (tci->speculative);
145510d565efSmrg 	      }
1456c7a68eb7Smrg 	    if (TREE_CODE (op) == MEM_REF)
145710d565efSmrg 	      {
145810d565efSmrg 		if (!tree_fits_shwi_p (TREE_OPERAND (op, 1)))
145910d565efSmrg 		  {
146010d565efSmrg                     tci->speculative++;
146110d565efSmrg 		    return csftc_abort_walking_p (tci->speculative);
146210d565efSmrg 		  }
146310d565efSmrg 		offset += tree_to_shwi (TREE_OPERAND (op, 1))
146410d565efSmrg 			  * BITS_PER_UNIT;
146510d565efSmrg 		op = TREE_OPERAND (op, 0);
146610d565efSmrg 	      }
146710d565efSmrg 	    else if (DECL_P (op))
146810d565efSmrg 	      ;
146910d565efSmrg 	    else
147010d565efSmrg 	      {
147110d565efSmrg                 tci->speculative++;
147210d565efSmrg 	        return csftc_abort_walking_p (tci->speculative);
147310d565efSmrg 	      }
147410d565efSmrg 	    op = walk_ssa_copies (op);
147510d565efSmrg 	  }
147610d565efSmrg 	if (operand_equal_p (op, tci->instance, 0)
147710d565efSmrg 	    && TYPE_SIZE (type)
147810d565efSmrg 	    && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
147910d565efSmrg 	    && tree_fits_shwi_p (TYPE_SIZE (type))
148010d565efSmrg 	    && tree_to_shwi (TYPE_SIZE (type)) + offset > tci->offset
148110d565efSmrg 	    /* Some inlined constructors may look as follows:
148210d565efSmrg 		  _3 = operator new (16);
148310d565efSmrg 		  MEM[(struct  &)_3] ={v} {CLOBBER};
148410d565efSmrg 		  MEM[(struct CompositeClass *)_3]._vptr.CompositeClass
148510d565efSmrg 		    = &MEM[(void *)&_ZTV14CompositeClass + 16B];
148610d565efSmrg 		  _7 = &MEM[(struct CompositeClass *)_3].object;
148710d565efSmrg 		  EmptyClass::EmptyClass (_7);
148810d565efSmrg 
148910d565efSmrg 	       When determining dynamic type of _3 and because we stop at first
149010d565efSmrg 	       dynamic type found, we would stop on EmptyClass::EmptyClass (_7).
149110d565efSmrg 	       In this case the emptyclass is not even polymorphic and we miss
149210d565efSmrg 	       it is contained in an outer type that is polymorphic.  */
149310d565efSmrg 
149410d565efSmrg 	    && (tci->offset == offset || contains_polymorphic_type_p (type)))
149510d565efSmrg 	  {
149610d565efSmrg 	    record_known_type (tci, type, tci->offset - offset);
149710d565efSmrg 	    return true;
149810d565efSmrg 	  }
149910d565efSmrg       }
150010d565efSmrg      /* Calls may possibly change dynamic type by placement new. Assume
150110d565efSmrg         it will not happen, but make result speculative only.  */
150210d565efSmrg      if (dump_file)
150310d565efSmrg 	{
150410d565efSmrg           fprintf (dump_file, "  Function call may change dynamic type:");
1505c7a68eb7Smrg 	  print_gimple_stmt (dump_file, stmt, 0);
150610d565efSmrg 	}
150710d565efSmrg      tci->speculative++;
150810d565efSmrg      return csftc_abort_walking_p (tci->speculative);
150910d565efSmrg    }
151010d565efSmrg   /* Check for inlined virtual table store.  */
151110d565efSmrg   else if (noncall_stmt_may_be_vtbl_ptr_store (stmt))
151210d565efSmrg     {
151310d565efSmrg       tree type;
151410d565efSmrg       HOST_WIDE_INT offset = 0;
151510d565efSmrg       if (dump_file)
151610d565efSmrg 	{
151710d565efSmrg 	  fprintf (dump_file, "  Checking vtbl store: ");
1518c7a68eb7Smrg 	  print_gimple_stmt (dump_file, stmt, 0);
151910d565efSmrg 	}
152010d565efSmrg 
152110d565efSmrg       type = extr_type_from_vtbl_ptr_store (stmt, tci, &offset);
152210d565efSmrg       if (type == error_mark_node)
152310d565efSmrg 	return false;
152410d565efSmrg       gcc_assert (!type || TYPE_MAIN_VARIANT (type) == type);
152510d565efSmrg       if (!type)
152610d565efSmrg 	{
152710d565efSmrg 	  if (dump_file)
152810d565efSmrg 	    fprintf (dump_file, "  Unanalyzed store may change type.\n");
152910d565efSmrg 	  tci->seen_unanalyzed_store = true;
153010d565efSmrg 	  tci->speculative++;
153110d565efSmrg 	}
153210d565efSmrg       else
153310d565efSmrg         record_known_type (tci, type, offset);
153410d565efSmrg       return true;
153510d565efSmrg     }
153610d565efSmrg   else
153710d565efSmrg     return false;
153810d565efSmrg }
153910d565efSmrg 
154010d565efSmrg /* THIS is polymorphic call context obtained from get_polymorphic_context.
154110d565efSmrg    OTR_OBJECT is pointer to the instance returned by OBJ_TYPE_REF_OBJECT.
154210d565efSmrg    INSTANCE is pointer to the outer instance as returned by
154310d565efSmrg    get_polymorphic_context.  To avoid creation of temporary expressions,
154410d565efSmrg    INSTANCE may also be an declaration of get_polymorphic_context found the
154510d565efSmrg    value to be in static storage.
154610d565efSmrg 
154710d565efSmrg    If the type of instance is not fully determined
154810d565efSmrg    (either OUTER_TYPE is unknown or MAYBE_IN_CONSTRUCTION/INCLUDE_DERIVED_TYPES
154910d565efSmrg    is set), try to walk memory writes and find the actual construction of the
155010d565efSmrg    instance.
155110d565efSmrg 
155210d565efSmrg    Return true if memory is unchanged from function entry.
155310d565efSmrg 
155410d565efSmrg    We do not include this analysis in the context analysis itself, because
155510d565efSmrg    it needs memory SSA to be fully built and the walk may be expensive.
15560fc04c29Smrg    So it is not suitable for use withing fold_stmt and similar uses.
15570fc04c29Smrg 
15580fc04c29Smrg    AA_WALK_BUDGET_P, if not NULL, is how statements we should allow
15590fc04c29Smrg    walk_aliased_vdefs to examine.  The value should be decremented by the
1560*ec02198aSmrg    number of statements we examined or set to zero if exhausted.  */
156110d565efSmrg 
156210d565efSmrg bool
get_dynamic_type(tree instance,tree otr_object,tree otr_type,gimple * call,unsigned * aa_walk_budget_p)156310d565efSmrg ipa_polymorphic_call_context::get_dynamic_type (tree instance,
156410d565efSmrg 						tree otr_object,
156510d565efSmrg 						tree otr_type,
15660fc04c29Smrg 						gimple *call,
15670fc04c29Smrg 						unsigned *aa_walk_budget_p)
156810d565efSmrg {
156910d565efSmrg   struct type_change_info tci;
157010d565efSmrg   ao_ref ao;
157110d565efSmrg   bool function_entry_reached = false;
157210d565efSmrg   tree instance_ref = NULL;
157310d565efSmrg   gimple *stmt = call;
157410d565efSmrg   /* Remember OFFSET before it is modified by restrict_to_inner_class.
157510d565efSmrg      This is because we do not update INSTANCE when walking inwards.  */
157610d565efSmrg   HOST_WIDE_INT instance_offset = offset;
157710d565efSmrg   tree instance_outer_type = outer_type;
157810d565efSmrg 
1579c7a68eb7Smrg   if (!instance)
1580c7a68eb7Smrg     return false;
1581c7a68eb7Smrg 
158210d565efSmrg   if (otr_type)
158310d565efSmrg     otr_type = TYPE_MAIN_VARIANT (otr_type);
158410d565efSmrg 
158510d565efSmrg   /* Walk into inner type. This may clear maybe_derived_type and save us
1586*ec02198aSmrg      from useless work.  It also makes later comparisons with static type
158710d565efSmrg      easier.  */
158810d565efSmrg   if (outer_type && otr_type)
158910d565efSmrg     {
159010d565efSmrg       if (!restrict_to_inner_class (otr_type))
159110d565efSmrg         return false;
159210d565efSmrg     }
159310d565efSmrg 
159410d565efSmrg   if (!maybe_in_construction && !maybe_derived_type)
159510d565efSmrg     return false;
159610d565efSmrg 
159710d565efSmrg   /* If we are in fact not looking at any object object or the instance is
159810d565efSmrg      some placement new into a random load, give up straight away.  */
159910d565efSmrg   if (TREE_CODE (instance) == MEM_REF)
160010d565efSmrg     return false;
160110d565efSmrg 
1602*ec02198aSmrg   /* We need to obtain reference to virtual table pointer.  It is better
160310d565efSmrg      to look it up in the code rather than build our own.  This require bit
160410d565efSmrg      of pattern matching, but we end up verifying that what we found is
160510d565efSmrg      correct.
160610d565efSmrg 
160710d565efSmrg      What we pattern match is:
160810d565efSmrg 
160910d565efSmrg        tmp = instance->_vptr.A;   // vtbl ptr load
161010d565efSmrg        tmp2 = tmp[otr_token];	  // vtable lookup
161110d565efSmrg        OBJ_TYPE_REF(tmp2;instance->0) (instance);
161210d565efSmrg 
161310d565efSmrg      We want to start alias oracle walk from vtbl pointer load,
161410d565efSmrg      but we may not be able to identify it, for example, when PRE moved the
161510d565efSmrg      load around.  */
161610d565efSmrg 
161710d565efSmrg   if (gimple_code (call) == GIMPLE_CALL)
161810d565efSmrg     {
161910d565efSmrg       tree ref = gimple_call_fn (call);
162010d565efSmrg       bool reverse;
162110d565efSmrg 
162210d565efSmrg       if (TREE_CODE (ref) == OBJ_TYPE_REF)
162310d565efSmrg 	{
162410d565efSmrg 	  ref = OBJ_TYPE_REF_EXPR (ref);
162510d565efSmrg 	  ref = walk_ssa_copies (ref);
162610d565efSmrg 
162710d565efSmrg 	  /* If call target is already known, no need to do the expensive
162810d565efSmrg  	     memory walk.  */
162910d565efSmrg 	  if (is_gimple_min_invariant (ref))
163010d565efSmrg 	    return false;
163110d565efSmrg 
163210d565efSmrg 	  /* Check if definition looks like vtable lookup.  */
163310d565efSmrg 	  if (TREE_CODE (ref) == SSA_NAME
163410d565efSmrg 	      && !SSA_NAME_IS_DEFAULT_DEF (ref)
163510d565efSmrg 	      && gimple_assign_load_p (SSA_NAME_DEF_STMT (ref))
163610d565efSmrg 	      && TREE_CODE (gimple_assign_rhs1
163710d565efSmrg 			     (SSA_NAME_DEF_STMT (ref))) == MEM_REF)
163810d565efSmrg 	    {
163910d565efSmrg 	      ref = get_base_address
164010d565efSmrg 		     (TREE_OPERAND (gimple_assign_rhs1
164110d565efSmrg 				     (SSA_NAME_DEF_STMT (ref)), 0));
164210d565efSmrg 	      ref = walk_ssa_copies (ref);
164310d565efSmrg 	      /* Find base address of the lookup and see if it looks like
164410d565efSmrg 		 vptr load.  */
164510d565efSmrg 	      if (TREE_CODE (ref) == SSA_NAME
164610d565efSmrg 		  && !SSA_NAME_IS_DEFAULT_DEF (ref)
164710d565efSmrg 		  && gimple_assign_load_p (SSA_NAME_DEF_STMT (ref)))
164810d565efSmrg 		{
1649c7a68eb7Smrg 		  HOST_WIDE_INT offset2, size;
165010d565efSmrg 		  tree ref_exp = gimple_assign_rhs1 (SSA_NAME_DEF_STMT (ref));
165110d565efSmrg 		  tree base_ref
1652c7a68eb7Smrg 		    = get_ref_base_and_extent_hwi (ref_exp, &offset2,
1653c7a68eb7Smrg 						   &size, &reverse);
165410d565efSmrg 
165510d565efSmrg 		  /* Finally verify that what we found looks like read from
165610d565efSmrg 		     OTR_OBJECT or from INSTANCE with offset OFFSET.  */
165710d565efSmrg 		  if (base_ref
165810d565efSmrg 		      && ((TREE_CODE (base_ref) == MEM_REF
165910d565efSmrg 		           && ((offset2 == instance_offset
166010d565efSmrg 		                && TREE_OPERAND (base_ref, 0) == instance)
166110d565efSmrg 			       || (!offset2
166210d565efSmrg 				   && TREE_OPERAND (base_ref, 0)
166310d565efSmrg 				      == otr_object)))
166410d565efSmrg 			  || (DECL_P (instance) && base_ref == instance
166510d565efSmrg 			      && offset2 == instance_offset)))
166610d565efSmrg 		    {
166710d565efSmrg 		      stmt = SSA_NAME_DEF_STMT (ref);
166810d565efSmrg 		      instance_ref = ref_exp;
166910d565efSmrg 		    }
167010d565efSmrg 		}
167110d565efSmrg 	    }
167210d565efSmrg 	}
167310d565efSmrg     }
167410d565efSmrg 
167510d565efSmrg   /* If we failed to look up the reference in code, build our own.  */
167610d565efSmrg   if (!instance_ref)
167710d565efSmrg     {
167810d565efSmrg       /* If the statement in question does not use memory, we can't tell
167910d565efSmrg 	 anything.  */
168010d565efSmrg       if (!gimple_vuse (stmt))
168110d565efSmrg 	return false;
168210d565efSmrg       ao_ref_init_from_ptr_and_size (&ao, otr_object, NULL);
168310d565efSmrg     }
168410d565efSmrg   else
168510d565efSmrg   /* Otherwise use the real reference.  */
168610d565efSmrg     ao_ref_init (&ao, instance_ref);
168710d565efSmrg 
168810d565efSmrg   /* We look for vtbl pointer read.  */
168910d565efSmrg   ao.size = POINTER_SIZE;
169010d565efSmrg   ao.max_size = ao.size;
169110d565efSmrg   /* We are looking for stores to vptr pointer within the instance of
169210d565efSmrg      outer type.
169310d565efSmrg      TODO: The vptr pointer type is globally known, we probably should
169410d565efSmrg      keep it and do that even when otr_type is unknown.  */
169510d565efSmrg   if (otr_type)
169610d565efSmrg     {
169710d565efSmrg       ao.base_alias_set
169810d565efSmrg 	= get_alias_set (outer_type ? outer_type : otr_type);
169910d565efSmrg       ao.ref_alias_set
170010d565efSmrg         = get_alias_set (TREE_TYPE (BINFO_VTABLE (TYPE_BINFO (otr_type))));
170110d565efSmrg     }
170210d565efSmrg 
170310d565efSmrg   if (dump_file)
170410d565efSmrg     {
170510d565efSmrg       fprintf (dump_file, "Determining dynamic type for call: ");
1706c7a68eb7Smrg       print_gimple_stmt (dump_file, call, 0);
170710d565efSmrg       fprintf (dump_file, "  Starting walk at: ");
1708c7a68eb7Smrg       print_gimple_stmt (dump_file, stmt, 0);
170910d565efSmrg       fprintf (dump_file, "  instance pointer: ");
171010d565efSmrg       print_generic_expr (dump_file, otr_object, TDF_SLIM);
171110d565efSmrg       fprintf (dump_file, "  Outer instance pointer: ");
171210d565efSmrg       print_generic_expr (dump_file, instance, TDF_SLIM);
171310d565efSmrg       fprintf (dump_file, " offset: %i (bits)", (int)instance_offset);
171410d565efSmrg       fprintf (dump_file, " vtbl reference: ");
171510d565efSmrg       print_generic_expr (dump_file, instance_ref, TDF_SLIM);
171610d565efSmrg       fprintf (dump_file, "\n");
171710d565efSmrg     }
171810d565efSmrg 
171910d565efSmrg   tci.offset = instance_offset;
172010d565efSmrg   tci.instance = instance;
172110d565efSmrg   tci.vtbl_ptr_ref = instance_ref;
172210d565efSmrg   tci.known_current_type = NULL_TREE;
172310d565efSmrg   tci.known_current_offset = 0;
172410d565efSmrg   tci.otr_type = otr_type;
172510d565efSmrg   tci.type_maybe_changed = false;
172610d565efSmrg   tci.multiple_types_encountered = false;
172710d565efSmrg   tci.speculative = 0;
172810d565efSmrg   tci.seen_unanalyzed_store = false;
172910d565efSmrg 
17300fc04c29Smrg   unsigned aa_walk_budget = 0;
17310fc04c29Smrg   if (aa_walk_budget_p)
17320fc04c29Smrg     aa_walk_budget = *aa_walk_budget_p + 1;
17330fc04c29Smrg 
17340fc04c29Smrg   int walked
17350fc04c29Smrg    = walk_aliased_vdefs (&ao, gimple_vuse (stmt), check_stmt_for_type_change,
17360fc04c29Smrg 			 &tci, NULL, &function_entry_reached, aa_walk_budget);
173710d565efSmrg 
173810d565efSmrg   /* If we did not find any type changing statements, we may still drop
173910d565efSmrg      maybe_in_construction flag if the context already have outer type.
174010d565efSmrg 
174110d565efSmrg      Here we make special assumptions about both constructors and
174210d565efSmrg      destructors which are all the functions that are allowed to alter the
174310d565efSmrg      VMT pointers.  It assumes that destructors begin with assignment into
174410d565efSmrg      all VMT pointers and that constructors essentially look in the
174510d565efSmrg      following way:
174610d565efSmrg 
174710d565efSmrg      1) The very first thing they do is that they call constructors of
174810d565efSmrg      ancestor sub-objects that have them.
174910d565efSmrg 
175010d565efSmrg      2) Then VMT pointers of this and all its ancestors is set to new
175110d565efSmrg      values corresponding to the type corresponding to the constructor.
175210d565efSmrg 
175310d565efSmrg      3) Only afterwards, other stuff such as constructor of member
175410d565efSmrg      sub-objects and the code written by the user is run.  Only this may
175510d565efSmrg      include calling virtual functions, directly or indirectly.
175610d565efSmrg 
175710d565efSmrg      4) placement new cannot be used to change type of non-POD statically
175810d565efSmrg      allocated variables.
175910d565efSmrg 
176010d565efSmrg      There is no way to call a constructor of an ancestor sub-object in any
176110d565efSmrg      other way.
176210d565efSmrg 
176310d565efSmrg      This means that we do not have to care whether constructors get the
176410d565efSmrg      correct type information because they will always change it (in fact,
176510d565efSmrg      if we define the type to be given by the VMT pointer, it is undefined).
176610d565efSmrg 
176710d565efSmrg      The most important fact to derive from the above is that if, for some
176810d565efSmrg      statement in the section 3, we try to detect whether the dynamic type
176910d565efSmrg      has changed, we can safely ignore all calls as we examine the function
177010d565efSmrg      body backwards until we reach statements in section 2 because these
177110d565efSmrg      calls cannot be ancestor constructors or destructors (if the input is
177210d565efSmrg      not bogus) and so do not change the dynamic type (this holds true only
177310d565efSmrg      for automatically allocated objects but at the moment we devirtualize
177410d565efSmrg      only these).  We then must detect that statements in section 2 change
177510d565efSmrg      the dynamic type and can try to derive the new type.  That is enough
177610d565efSmrg      and we can stop, we will never see the calls into constructors of
177710d565efSmrg      sub-objects in this code.
177810d565efSmrg 
177910d565efSmrg      Therefore if the static outer type was found (outer_type)
178010d565efSmrg      we can safely ignore tci.speculative that is set on calls and give up
1781*ec02198aSmrg      only if there was dynamic type store that may affect given variable
178210d565efSmrg      (seen_unanalyzed_store)  */
178310d565efSmrg 
17840fc04c29Smrg   if (walked < 0)
17850fc04c29Smrg     {
17860fc04c29Smrg       if (dump_file)
17870fc04c29Smrg 	fprintf (dump_file, "  AA walk budget exhausted.\n");
17880fc04c29Smrg       *aa_walk_budget_p = 0;
17890fc04c29Smrg       return false;
17900fc04c29Smrg     }
17910fc04c29Smrg   else if (aa_walk_budget_p)
17920fc04c29Smrg     *aa_walk_budget_p -= walked;
17930fc04c29Smrg 
179410d565efSmrg   if (!tci.type_maybe_changed
179510d565efSmrg       || (outer_type
179610d565efSmrg 	  && !dynamic
179710d565efSmrg 	  && !tci.seen_unanalyzed_store
179810d565efSmrg 	  && !tci.multiple_types_encountered
179910d565efSmrg 	  && ((offset == tci.offset
180010d565efSmrg 	       && types_same_for_odr (tci.known_current_type,
180110d565efSmrg 				      outer_type))
180210d565efSmrg 	       || (instance_offset == offset
180310d565efSmrg 		   && types_same_for_odr (tci.known_current_type,
180410d565efSmrg 					  instance_outer_type)))))
180510d565efSmrg     {
180610d565efSmrg       if (!outer_type || tci.seen_unanalyzed_store)
180710d565efSmrg 	return false;
180810d565efSmrg       if (maybe_in_construction)
180910d565efSmrg         maybe_in_construction = false;
181010d565efSmrg       if (dump_file)
181110d565efSmrg 	fprintf (dump_file, "  No dynamic type change found.\n");
181210d565efSmrg       return true;
181310d565efSmrg     }
181410d565efSmrg 
181510d565efSmrg   if (tci.known_current_type
181610d565efSmrg       && !function_entry_reached
181710d565efSmrg       && !tci.multiple_types_encountered)
181810d565efSmrg     {
181910d565efSmrg       if (!tci.speculative)
182010d565efSmrg 	{
182110d565efSmrg 	  outer_type = TYPE_MAIN_VARIANT (tci.known_current_type);
182210d565efSmrg 	  offset = tci.known_current_offset;
182310d565efSmrg 	  dynamic = true;
182410d565efSmrg 	  maybe_in_construction = false;
182510d565efSmrg 	  maybe_derived_type = false;
182610d565efSmrg 	  if (dump_file)
182710d565efSmrg 	    fprintf (dump_file, "  Determined dynamic type.\n");
182810d565efSmrg 	}
182910d565efSmrg       else if (!speculative_outer_type
183010d565efSmrg 	       || speculative_maybe_derived_type)
183110d565efSmrg 	{
183210d565efSmrg 	  speculative_outer_type = TYPE_MAIN_VARIANT (tci.known_current_type);
183310d565efSmrg 	  speculative_offset = tci.known_current_offset;
183410d565efSmrg 	  speculative_maybe_derived_type = false;
183510d565efSmrg 	  if (dump_file)
183610d565efSmrg 	    fprintf (dump_file, "  Determined speculative dynamic type.\n");
183710d565efSmrg 	}
183810d565efSmrg     }
183910d565efSmrg   else if (dump_file)
184010d565efSmrg     {
184110d565efSmrg       fprintf (dump_file, "  Found multiple types%s%s\n",
184210d565efSmrg 	       function_entry_reached ? " (function entry reached)" : "",
184310d565efSmrg 	       function_entry_reached ? " (multiple types encountered)" : "");
184410d565efSmrg     }
184510d565efSmrg 
184610d565efSmrg   return false;
184710d565efSmrg }
184810d565efSmrg 
184910d565efSmrg /* See if speculation given by SPEC_OUTER_TYPE, SPEC_OFFSET and SPEC_MAYBE_DERIVED_TYPE
185010d565efSmrg    seems consistent (and useful) with what we already have in the non-speculative context.  */
185110d565efSmrg 
185210d565efSmrg bool
speculation_consistent_p(tree spec_outer_type,HOST_WIDE_INT spec_offset,bool spec_maybe_derived_type,tree otr_type)185310d565efSmrg ipa_polymorphic_call_context::speculation_consistent_p (tree spec_outer_type,
185410d565efSmrg 							HOST_WIDE_INT spec_offset,
185510d565efSmrg 							bool spec_maybe_derived_type,
185610d565efSmrg 							tree otr_type) const
185710d565efSmrg {
185810d565efSmrg   if (!flag_devirtualize_speculatively)
185910d565efSmrg     return false;
186010d565efSmrg 
186110d565efSmrg   /* Non-polymorphic types are useless for deriving likely polymorphic
186210d565efSmrg      call targets.  */
186310d565efSmrg   if (!spec_outer_type || !contains_polymorphic_type_p (spec_outer_type))
186410d565efSmrg     return false;
186510d565efSmrg 
186610d565efSmrg   /* If we know nothing, speculation is always good.  */
186710d565efSmrg   if (!outer_type)
186810d565efSmrg     return true;
186910d565efSmrg 
187010d565efSmrg   /* Speculation is only useful to avoid derived types.
187110d565efSmrg      This is not 100% true for placement new, where the outer context may
187210d565efSmrg      turn out to be useless, but ignore these for now.  */
187310d565efSmrg   if (!maybe_derived_type)
187410d565efSmrg     return false;
187510d565efSmrg 
187610d565efSmrg   /* If types agrees, speculation is consistent, but it makes sense only
187710d565efSmrg      when it says something new.  */
187810d565efSmrg   if (types_must_be_same_for_odr (spec_outer_type, outer_type))
187910d565efSmrg     return maybe_derived_type && !spec_maybe_derived_type;
188010d565efSmrg 
188110d565efSmrg   /* If speculation does not contain the type in question, ignore it.  */
188210d565efSmrg   if (otr_type
188310d565efSmrg       && !contains_type_p (spec_outer_type, spec_offset, otr_type, false, true))
188410d565efSmrg     return false;
188510d565efSmrg 
188610d565efSmrg   /* If outer type already contains speculation as a filed,
188710d565efSmrg      it is useless.  We already know from OUTER_TYPE
188810d565efSmrg      SPEC_TYPE and that it is not in the construction.  */
188910d565efSmrg   if (contains_type_p (outer_type, offset - spec_offset,
189010d565efSmrg 		       spec_outer_type, false, false))
189110d565efSmrg     return false;
189210d565efSmrg 
189310d565efSmrg   /* If speculative outer type is not more specified than outer
189410d565efSmrg      type, just give up.
189510d565efSmrg      We can only decide this safely if we can compare types with OUTER_TYPE.
189610d565efSmrg    */
189710d565efSmrg   if ((!in_lto_p || odr_type_p (outer_type))
189810d565efSmrg       && !contains_type_p (spec_outer_type,
189910d565efSmrg 			   spec_offset - offset,
190010d565efSmrg 			   outer_type, false))
190110d565efSmrg     return false;
190210d565efSmrg   return true;
190310d565efSmrg }
190410d565efSmrg 
190510d565efSmrg /* Improve THIS with speculation described by NEW_OUTER_TYPE, NEW_OFFSET,
190610d565efSmrg    NEW_MAYBE_DERIVED_TYPE
190710d565efSmrg    If OTR_TYPE is set, assume the context is used with OTR_TYPE.  */
190810d565efSmrg 
190910d565efSmrg bool
combine_speculation_with(tree new_outer_type,HOST_WIDE_INT new_offset,bool new_maybe_derived_type,tree otr_type)191010d565efSmrg ipa_polymorphic_call_context::combine_speculation_with
191110d565efSmrg    (tree new_outer_type, HOST_WIDE_INT new_offset, bool new_maybe_derived_type,
191210d565efSmrg     tree otr_type)
191310d565efSmrg {
191410d565efSmrg   if (!new_outer_type)
191510d565efSmrg     return false;
191610d565efSmrg 
191710d565efSmrg   /* restrict_to_inner_class may eliminate wrong speculation making our job
1918*ec02198aSmrg      easier.  */
191910d565efSmrg   if (otr_type)
192010d565efSmrg     restrict_to_inner_class (otr_type);
192110d565efSmrg 
192210d565efSmrg   if (!speculation_consistent_p (new_outer_type, new_offset,
192310d565efSmrg 				 new_maybe_derived_type, otr_type))
192410d565efSmrg     return false;
192510d565efSmrg 
192610d565efSmrg   /* New speculation is a win in case we have no speculation or new
192710d565efSmrg      speculation does not consider derivations.  */
192810d565efSmrg   if (!speculative_outer_type
192910d565efSmrg       || (speculative_maybe_derived_type
193010d565efSmrg 	  && !new_maybe_derived_type))
193110d565efSmrg     {
193210d565efSmrg       speculative_outer_type = new_outer_type;
193310d565efSmrg       speculative_offset = new_offset;
193410d565efSmrg       speculative_maybe_derived_type = new_maybe_derived_type;
193510d565efSmrg       return true;
193610d565efSmrg     }
193710d565efSmrg   else if (types_must_be_same_for_odr (speculative_outer_type,
193810d565efSmrg 				       new_outer_type))
193910d565efSmrg     {
194010d565efSmrg       if (speculative_offset != new_offset)
194110d565efSmrg 	{
194210d565efSmrg 	  /* OK we have two contexts that seems valid but they disagree,
194310d565efSmrg 	     just give up.
194410d565efSmrg 
194510d565efSmrg 	     This is not a lattice operation, so we may want to drop it later.  */
194610d565efSmrg 	  if (dump_file && (dump_flags & TDF_DETAILS))
194710d565efSmrg 	    fprintf (dump_file,
194810d565efSmrg 		     "Speculative outer types match, "
194910d565efSmrg 		     "offset mismatch -> invalid speculation\n");
195010d565efSmrg 	  clear_speculation ();
195110d565efSmrg 	  return true;
195210d565efSmrg 	}
195310d565efSmrg       else
195410d565efSmrg 	{
195510d565efSmrg 	  if (speculative_maybe_derived_type && !new_maybe_derived_type)
195610d565efSmrg 	    {
195710d565efSmrg 	      speculative_maybe_derived_type = false;
195810d565efSmrg 	      return true;
195910d565efSmrg 	    }
196010d565efSmrg 	  else
196110d565efSmrg 	    return false;
196210d565efSmrg 	}
196310d565efSmrg     }
196410d565efSmrg   /* Choose type that contains the other.  This one either contains the outer
196510d565efSmrg      as a field (thus giving exactly one target) or is deeper in the type
1966*ec02198aSmrg      hierarchy.  */
196710d565efSmrg   else if (speculative_outer_type
196810d565efSmrg 	   && speculative_maybe_derived_type
196910d565efSmrg 	   && (new_offset > speculative_offset
197010d565efSmrg 	       || (new_offset == speculative_offset
197110d565efSmrg 		   && contains_type_p (new_outer_type,
197210d565efSmrg 				       0, speculative_outer_type, false))))
197310d565efSmrg     {
197410d565efSmrg       tree old_outer_type = speculative_outer_type;
197510d565efSmrg       HOST_WIDE_INT old_offset = speculative_offset;
197610d565efSmrg       bool old_maybe_derived_type = speculative_maybe_derived_type;
197710d565efSmrg 
197810d565efSmrg       speculative_outer_type = new_outer_type;
197910d565efSmrg       speculative_offset = new_offset;
198010d565efSmrg       speculative_maybe_derived_type = new_maybe_derived_type;
198110d565efSmrg 
198210d565efSmrg       if (otr_type)
198310d565efSmrg 	restrict_to_inner_class (otr_type);
198410d565efSmrg 
198510d565efSmrg       /* If the speculation turned out to make no sense, revert to sensible
198610d565efSmrg 	 one.  */
198710d565efSmrg       if (!speculative_outer_type)
198810d565efSmrg 	{
198910d565efSmrg 	  speculative_outer_type = old_outer_type;
199010d565efSmrg 	  speculative_offset = old_offset;
199110d565efSmrg 	  speculative_maybe_derived_type = old_maybe_derived_type;
199210d565efSmrg 	  return false;
199310d565efSmrg 	}
199410d565efSmrg       return (old_offset != speculative_offset
199510d565efSmrg 	      || old_maybe_derived_type != speculative_maybe_derived_type
199610d565efSmrg 	      || types_must_be_same_for_odr (speculative_outer_type,
199710d565efSmrg 					     new_outer_type));
199810d565efSmrg     }
199910d565efSmrg   return false;
200010d565efSmrg }
200110d565efSmrg 
200210d565efSmrg /* Make speculation less specific so
200310d565efSmrg    NEW_OUTER_TYPE, NEW_OFFSET, NEW_MAYBE_DERIVED_TYPE is also included.
200410d565efSmrg    If OTR_TYPE is set, assume the context is used with OTR_TYPE.  */
200510d565efSmrg 
200610d565efSmrg bool
meet_speculation_with(tree new_outer_type,HOST_WIDE_INT new_offset,bool new_maybe_derived_type,tree otr_type)200710d565efSmrg ipa_polymorphic_call_context::meet_speculation_with
200810d565efSmrg    (tree new_outer_type, HOST_WIDE_INT new_offset, bool new_maybe_derived_type,
200910d565efSmrg     tree otr_type)
201010d565efSmrg {
201110d565efSmrg   if (!new_outer_type && speculative_outer_type)
201210d565efSmrg     {
201310d565efSmrg       clear_speculation ();
201410d565efSmrg       return true;
201510d565efSmrg     }
201610d565efSmrg 
201710d565efSmrg   /* restrict_to_inner_class may eliminate wrong speculation making our job
2018*ec02198aSmrg      easier.  */
201910d565efSmrg   if (otr_type)
202010d565efSmrg     restrict_to_inner_class (otr_type);
202110d565efSmrg 
202210d565efSmrg   if (!speculative_outer_type
202310d565efSmrg       || !speculation_consistent_p (speculative_outer_type,
202410d565efSmrg 				    speculative_offset,
202510d565efSmrg 				    speculative_maybe_derived_type,
202610d565efSmrg 				    otr_type))
202710d565efSmrg     return false;
202810d565efSmrg 
202910d565efSmrg   if (!speculation_consistent_p (new_outer_type, new_offset,
203010d565efSmrg 				 new_maybe_derived_type, otr_type))
203110d565efSmrg     {
203210d565efSmrg       clear_speculation ();
203310d565efSmrg       return true;
203410d565efSmrg     }
203510d565efSmrg 
203610d565efSmrg   else if (types_must_be_same_for_odr (speculative_outer_type,
203710d565efSmrg 				       new_outer_type))
203810d565efSmrg     {
203910d565efSmrg       if (speculative_offset != new_offset)
204010d565efSmrg 	{
204110d565efSmrg 	  clear_speculation ();
204210d565efSmrg 	  return true;
204310d565efSmrg 	}
204410d565efSmrg       else
204510d565efSmrg 	{
204610d565efSmrg 	  if (!speculative_maybe_derived_type && new_maybe_derived_type)
204710d565efSmrg 	    {
204810d565efSmrg 	      speculative_maybe_derived_type = true;
204910d565efSmrg 	      return true;
205010d565efSmrg 	    }
205110d565efSmrg 	  else
205210d565efSmrg 	    return false;
205310d565efSmrg 	}
205410d565efSmrg     }
205510d565efSmrg   /* See if one type contains the other as a field (not base).  */
205610d565efSmrg   else if (contains_type_p (new_outer_type, new_offset - speculative_offset,
205710d565efSmrg 			    speculative_outer_type, false, false))
205810d565efSmrg     return false;
205910d565efSmrg   else if (contains_type_p (speculative_outer_type,
206010d565efSmrg 			    speculative_offset - new_offset,
206110d565efSmrg 			    new_outer_type, false, false))
206210d565efSmrg     {
206310d565efSmrg       speculative_outer_type = new_outer_type;
206410d565efSmrg       speculative_offset = new_offset;
206510d565efSmrg       speculative_maybe_derived_type = new_maybe_derived_type;
206610d565efSmrg       return true;
206710d565efSmrg     }
206810d565efSmrg   /* See if OUTER_TYPE is base of CTX.OUTER_TYPE.  */
206910d565efSmrg   else if (contains_type_p (new_outer_type,
207010d565efSmrg 			    new_offset - speculative_offset,
207110d565efSmrg 			    speculative_outer_type, false, true))
207210d565efSmrg     {
207310d565efSmrg       if (!speculative_maybe_derived_type)
207410d565efSmrg 	{
207510d565efSmrg 	  speculative_maybe_derived_type = true;
207610d565efSmrg 	  return true;
207710d565efSmrg 	}
207810d565efSmrg       return false;
207910d565efSmrg     }
208010d565efSmrg   /* See if CTX.OUTER_TYPE is base of OUTER_TYPE.  */
208110d565efSmrg   else if (contains_type_p (speculative_outer_type,
208210d565efSmrg 			    speculative_offset - new_offset, new_outer_type, false, true))
208310d565efSmrg     {
208410d565efSmrg       speculative_outer_type = new_outer_type;
208510d565efSmrg       speculative_offset = new_offset;
208610d565efSmrg       speculative_maybe_derived_type = true;
208710d565efSmrg       return true;
208810d565efSmrg     }
208910d565efSmrg   else
209010d565efSmrg     {
209110d565efSmrg       if (dump_file && (dump_flags & TDF_DETAILS))
209210d565efSmrg         fprintf (dump_file, "Giving up on speculative meet\n");
209310d565efSmrg       clear_speculation ();
209410d565efSmrg       return true;
209510d565efSmrg     }
209610d565efSmrg }
209710d565efSmrg 
2098*ec02198aSmrg /* Assume that both THIS and a given context is valid and strengthen THIS
2099*ec02198aSmrg    if possible.  Return true if any strengthening was made.
210010d565efSmrg    If actual type the context is being used in is known, OTR_TYPE should be
210110d565efSmrg    set accordingly. This improves quality of combined result.  */
210210d565efSmrg 
210310d565efSmrg bool
combine_with(ipa_polymorphic_call_context ctx,tree otr_type)210410d565efSmrg ipa_polymorphic_call_context::combine_with (ipa_polymorphic_call_context ctx,
210510d565efSmrg 					    tree otr_type)
210610d565efSmrg {
210710d565efSmrg   bool updated = false;
210810d565efSmrg 
210910d565efSmrg   if (ctx.useless_p () || invalid)
211010d565efSmrg     return false;
211110d565efSmrg 
211210d565efSmrg   /* Restricting context to inner type makes merging easier, however do not
211310d565efSmrg      do that unless we know how the context is used (OTR_TYPE is non-NULL)  */
211410d565efSmrg   if (otr_type && !invalid && !ctx.invalid)
211510d565efSmrg     {
211610d565efSmrg       restrict_to_inner_class (otr_type);
211710d565efSmrg       ctx.restrict_to_inner_class (otr_type);
211810d565efSmrg       if(invalid)
211910d565efSmrg         return false;
212010d565efSmrg     }
212110d565efSmrg 
212210d565efSmrg   if (dump_file && (dump_flags & TDF_DETAILS))
212310d565efSmrg     {
212410d565efSmrg       fprintf (dump_file, "Polymorphic call context combine:");
212510d565efSmrg       dump (dump_file);
212610d565efSmrg       fprintf (dump_file, "With context:                    ");
212710d565efSmrg       ctx.dump (dump_file);
212810d565efSmrg       if (otr_type)
212910d565efSmrg 	{
213010d565efSmrg           fprintf (dump_file, "To be used with type:            ");
213110d565efSmrg 	  print_generic_expr (dump_file, otr_type, TDF_SLIM);
213210d565efSmrg           fprintf (dump_file, "\n");
213310d565efSmrg 	}
213410d565efSmrg     }
213510d565efSmrg 
213610d565efSmrg   /* If call is known to be invalid, we are done.  */
213710d565efSmrg   if (ctx.invalid)
213810d565efSmrg     {
213910d565efSmrg       if (dump_file && (dump_flags & TDF_DETAILS))
214010d565efSmrg         fprintf (dump_file, "-> Invalid context\n");
214110d565efSmrg       goto invalidate;
214210d565efSmrg     }
214310d565efSmrg 
214410d565efSmrg   if (!ctx.outer_type)
214510d565efSmrg     ;
214610d565efSmrg   else if (!outer_type)
214710d565efSmrg     {
214810d565efSmrg       outer_type = ctx.outer_type;
214910d565efSmrg       offset = ctx.offset;
215010d565efSmrg       dynamic = ctx.dynamic;
215110d565efSmrg       maybe_in_construction = ctx.maybe_in_construction;
215210d565efSmrg       maybe_derived_type = ctx.maybe_derived_type;
215310d565efSmrg       updated = true;
215410d565efSmrg     }
215510d565efSmrg   /* If types are known to be same, merging is quite easy.  */
215610d565efSmrg   else if (types_must_be_same_for_odr (outer_type, ctx.outer_type))
215710d565efSmrg     {
215810d565efSmrg       if (offset != ctx.offset
215910d565efSmrg 	  && TYPE_SIZE (outer_type)
216010d565efSmrg 	  && TREE_CODE (TYPE_SIZE (outer_type)) == INTEGER_CST)
216110d565efSmrg 	{
216210d565efSmrg 	  if (dump_file && (dump_flags & TDF_DETAILS))
216310d565efSmrg 	    fprintf (dump_file, "Outer types match, offset mismatch -> invalid\n");
216410d565efSmrg 	  clear_speculation ();
216510d565efSmrg 	  clear_outer_type ();
216610d565efSmrg 	  invalid = true;
216710d565efSmrg 	  return true;
216810d565efSmrg 	}
216910d565efSmrg       if (dump_file && (dump_flags & TDF_DETAILS))
217010d565efSmrg         fprintf (dump_file, "Outer types match, merging flags\n");
217110d565efSmrg       if (maybe_in_construction && !ctx.maybe_in_construction)
217210d565efSmrg 	{
217310d565efSmrg 	  updated = true;
217410d565efSmrg 	  maybe_in_construction = false;
217510d565efSmrg 	}
217610d565efSmrg       if (maybe_derived_type && !ctx.maybe_derived_type)
217710d565efSmrg 	{
217810d565efSmrg 	  updated = true;
217910d565efSmrg 	  maybe_derived_type = false;
218010d565efSmrg 	}
218110d565efSmrg       if (dynamic && !ctx.dynamic)
218210d565efSmrg 	{
218310d565efSmrg 	  updated = true;
218410d565efSmrg 	  dynamic = false;
218510d565efSmrg 	}
218610d565efSmrg     }
218710d565efSmrg   /* If we know the type precisely, there is not much to improve.  */
218810d565efSmrg   else if (!maybe_derived_type && !maybe_in_construction
218910d565efSmrg 	   && !ctx.maybe_derived_type && !ctx.maybe_in_construction)
219010d565efSmrg     {
219110d565efSmrg       /* It may be easy to check if second context permits the first
219210d565efSmrg 	 and set INVALID otherwise.  This is not easy to do in general;
219310d565efSmrg 	 contains_type_p may return false negatives for non-comparable
219410d565efSmrg 	 types.
219510d565efSmrg 
219610d565efSmrg 	 If OTR_TYPE is known, we however can expect that
219710d565efSmrg 	 restrict_to_inner_class should have discovered the same base
219810d565efSmrg 	 type.  */
219910d565efSmrg       if (otr_type && !ctx.maybe_in_construction && !ctx.maybe_derived_type)
220010d565efSmrg 	{
220110d565efSmrg 	  if (dump_file && (dump_flags & TDF_DETAILS))
220210d565efSmrg 	    fprintf (dump_file, "Contextes disagree -> invalid\n");
220310d565efSmrg 	  goto invalidate;
220410d565efSmrg 	}
220510d565efSmrg     }
220610d565efSmrg   /* See if one type contains the other as a field (not base).
220710d565efSmrg      In this case we want to choose the wider type, because it contains
220810d565efSmrg      more information.  */
220910d565efSmrg   else if (contains_type_p (ctx.outer_type, ctx.offset - offset,
221010d565efSmrg 			    outer_type, false, false))
221110d565efSmrg     {
221210d565efSmrg       if (dump_file && (dump_flags & TDF_DETAILS))
221310d565efSmrg 	fprintf (dump_file, "Second type contain the first as a field\n");
221410d565efSmrg 
221510d565efSmrg       if (maybe_derived_type)
221610d565efSmrg 	{
221710d565efSmrg 	  outer_type = ctx.outer_type;
221810d565efSmrg 	  maybe_derived_type = ctx.maybe_derived_type;
221910d565efSmrg 	  offset = ctx.offset;
222010d565efSmrg 	  dynamic = ctx.dynamic;
222110d565efSmrg 	  updated = true;
222210d565efSmrg 	}
222310d565efSmrg 
22240fc04c29Smrg       /* If we do not know how the context is being used, we cannot
22250fc04c29Smrg 	 clear MAYBE_IN_CONSTRUCTION because it may be offseted
222610d565efSmrg 	 to other component of OUTER_TYPE later and we know nothing
222710d565efSmrg 	 about it.  */
222810d565efSmrg       if (otr_type && maybe_in_construction
222910d565efSmrg 	  && !ctx.maybe_in_construction)
223010d565efSmrg 	{
223110d565efSmrg           maybe_in_construction = false;
223210d565efSmrg 	  updated = true;
223310d565efSmrg 	}
223410d565efSmrg     }
223510d565efSmrg   else if (contains_type_p (outer_type, offset - ctx.offset,
223610d565efSmrg 			    ctx.outer_type, false, false))
223710d565efSmrg     {
223810d565efSmrg       if (dump_file && (dump_flags & TDF_DETAILS))
223910d565efSmrg 	fprintf (dump_file, "First type contain the second as a field\n");
224010d565efSmrg 
224110d565efSmrg       if (otr_type && maybe_in_construction
224210d565efSmrg 	  && !ctx.maybe_in_construction)
224310d565efSmrg 	{
224410d565efSmrg           maybe_in_construction = false;
224510d565efSmrg 	  updated = true;
224610d565efSmrg 	}
224710d565efSmrg     }
224810d565efSmrg   /* See if OUTER_TYPE is base of CTX.OUTER_TYPE.  */
224910d565efSmrg   else if (contains_type_p (ctx.outer_type,
225010d565efSmrg 			    ctx.offset - offset, outer_type, false, true))
225110d565efSmrg     {
225210d565efSmrg       if (dump_file && (dump_flags & TDF_DETAILS))
225310d565efSmrg 	fprintf (dump_file, "First type is base of second\n");
225410d565efSmrg       if (!maybe_derived_type)
225510d565efSmrg 	{
225610d565efSmrg 	  if (!ctx.maybe_in_construction
225710d565efSmrg 	      && types_odr_comparable (outer_type, ctx.outer_type))
225810d565efSmrg 	    {
225910d565efSmrg 	      if (dump_file && (dump_flags & TDF_DETAILS))
226010d565efSmrg 		fprintf (dump_file, "Second context does not permit base -> invalid\n");
226110d565efSmrg 	      goto invalidate;
226210d565efSmrg 	    }
226310d565efSmrg 	}
2264*ec02198aSmrg       /* Pick variant deeper in the hierarchy.  */
226510d565efSmrg       else
226610d565efSmrg 	{
226710d565efSmrg 	  outer_type = ctx.outer_type;
226810d565efSmrg 	  maybe_in_construction = ctx.maybe_in_construction;
226910d565efSmrg 	  maybe_derived_type = ctx.maybe_derived_type;
227010d565efSmrg 	  offset = ctx.offset;
227110d565efSmrg 	  dynamic = ctx.dynamic;
227210d565efSmrg           updated = true;
227310d565efSmrg 	}
227410d565efSmrg     }
227510d565efSmrg   /* See if CTX.OUTER_TYPE is base of OUTER_TYPE.  */
227610d565efSmrg   else if (contains_type_p (outer_type,
227710d565efSmrg 			    offset - ctx.offset, ctx.outer_type, false, true))
227810d565efSmrg     {
227910d565efSmrg       if (dump_file && (dump_flags & TDF_DETAILS))
228010d565efSmrg 	fprintf (dump_file, "Second type is base of first\n");
228110d565efSmrg       if (!ctx.maybe_derived_type)
228210d565efSmrg 	{
228310d565efSmrg 	  if (!maybe_in_construction
228410d565efSmrg 	      && types_odr_comparable (outer_type, ctx.outer_type))
228510d565efSmrg 	    {
228610d565efSmrg 	      if (dump_file && (dump_flags & TDF_DETAILS))
228710d565efSmrg 		fprintf (dump_file, "First context does not permit base -> invalid\n");
228810d565efSmrg 	      goto invalidate;
228910d565efSmrg 	    }
229010d565efSmrg 	  /* Pick the base type.  */
229110d565efSmrg 	  else if (maybe_in_construction)
229210d565efSmrg 	    {
229310d565efSmrg 	      outer_type = ctx.outer_type;
229410d565efSmrg 	      maybe_in_construction = ctx.maybe_in_construction;
229510d565efSmrg 	      maybe_derived_type = ctx.maybe_derived_type;
229610d565efSmrg 	      offset = ctx.offset;
229710d565efSmrg 	      dynamic = ctx.dynamic;
229810d565efSmrg 	      updated = true;
229910d565efSmrg 	    }
230010d565efSmrg 	}
230110d565efSmrg     }
2302*ec02198aSmrg   /* TODO handle merging using hierarchy. */
230310d565efSmrg   else if (dump_file && (dump_flags & TDF_DETAILS))
230410d565efSmrg     fprintf (dump_file, "Giving up on merge\n");
230510d565efSmrg 
230610d565efSmrg   updated |= combine_speculation_with (ctx.speculative_outer_type,
230710d565efSmrg 				       ctx.speculative_offset,
230810d565efSmrg 				       ctx.speculative_maybe_derived_type,
230910d565efSmrg 				       otr_type);
231010d565efSmrg 
231110d565efSmrg   if (updated && dump_file && (dump_flags & TDF_DETAILS))
231210d565efSmrg     {
231310d565efSmrg       fprintf (dump_file, "Updated as:                      ");
231410d565efSmrg       dump (dump_file);
231510d565efSmrg       fprintf (dump_file, "\n");
231610d565efSmrg     }
231710d565efSmrg   return updated;
231810d565efSmrg 
231910d565efSmrg invalidate:
232010d565efSmrg   invalid = true;
232110d565efSmrg   clear_speculation ();
232210d565efSmrg   clear_outer_type ();
232310d565efSmrg   return true;
232410d565efSmrg }
232510d565efSmrg 
232610d565efSmrg /* Take non-speculative info, merge it with speculative and clear speculation.
232710d565efSmrg    Used when we no longer manage to keep track of actual outer type, but we
232810d565efSmrg    think it is still there.
232910d565efSmrg 
233010d565efSmrg    If OTR_TYPE is set, the transformation can be done more effectively assuming
233110d565efSmrg    that context is going to be used only that way.  */
233210d565efSmrg 
233310d565efSmrg void
make_speculative(tree otr_type)233410d565efSmrg ipa_polymorphic_call_context::make_speculative (tree otr_type)
233510d565efSmrg {
233610d565efSmrg   tree spec_outer_type = outer_type;
233710d565efSmrg   HOST_WIDE_INT spec_offset = offset;
233810d565efSmrg   bool spec_maybe_derived_type = maybe_derived_type;
233910d565efSmrg 
234010d565efSmrg   if (invalid)
234110d565efSmrg     {
234210d565efSmrg       invalid = false;
234310d565efSmrg       clear_outer_type ();
234410d565efSmrg       clear_speculation ();
234510d565efSmrg       return;
234610d565efSmrg     }
234710d565efSmrg   if (!outer_type)
234810d565efSmrg     return;
234910d565efSmrg   clear_outer_type ();
235010d565efSmrg   combine_speculation_with (spec_outer_type, spec_offset,
235110d565efSmrg 			    spec_maybe_derived_type,
235210d565efSmrg 			    otr_type);
235310d565efSmrg }
235410d565efSmrg 
235510d565efSmrg /* Use when we cannot track dynamic type change.  This speculatively assume
235610d565efSmrg    type change is not happening.  */
235710d565efSmrg 
235810d565efSmrg void
possible_dynamic_type_change(bool in_poly_cdtor,tree otr_type)235910d565efSmrg ipa_polymorphic_call_context::possible_dynamic_type_change (bool in_poly_cdtor,
236010d565efSmrg 							    tree otr_type)
236110d565efSmrg {
236210d565efSmrg   if (dynamic)
236310d565efSmrg     make_speculative (otr_type);
236410d565efSmrg   else if (in_poly_cdtor)
236510d565efSmrg     maybe_in_construction = true;
236610d565efSmrg }
236710d565efSmrg 
236810d565efSmrg /* Return TRUE if this context conveys the same information as OTHER.  */
236910d565efSmrg 
237010d565efSmrg bool
equal_to(const ipa_polymorphic_call_context & x)237110d565efSmrg ipa_polymorphic_call_context::equal_to
237210d565efSmrg     (const ipa_polymorphic_call_context &x) const
237310d565efSmrg {
237410d565efSmrg   if (useless_p ())
237510d565efSmrg     return x.useless_p ();
237610d565efSmrg   if (invalid)
237710d565efSmrg     return x.invalid;
237810d565efSmrg   if (x.useless_p () || x.invalid)
237910d565efSmrg     return false;
238010d565efSmrg 
238110d565efSmrg   if (outer_type)
238210d565efSmrg     {
238310d565efSmrg       if (!x.outer_type
238410d565efSmrg 	  || !types_odr_comparable (outer_type, x.outer_type)
238510d565efSmrg 	  || !types_same_for_odr (outer_type, x.outer_type)
238610d565efSmrg 	  || offset != x.offset
238710d565efSmrg 	  || maybe_in_construction != x.maybe_in_construction
238810d565efSmrg 	  || maybe_derived_type != x.maybe_derived_type
238910d565efSmrg 	  || dynamic != x.dynamic)
239010d565efSmrg 	return false;
239110d565efSmrg     }
239210d565efSmrg   else if (x.outer_type)
239310d565efSmrg     return false;
239410d565efSmrg 
239510d565efSmrg 
239610d565efSmrg   if (speculative_outer_type
239710d565efSmrg       && speculation_consistent_p (speculative_outer_type, speculative_offset,
239810d565efSmrg 				   speculative_maybe_derived_type, NULL_TREE))
239910d565efSmrg     {
240010d565efSmrg       if (!x.speculative_outer_type)
240110d565efSmrg 	return false;
240210d565efSmrg 
240310d565efSmrg       if (!types_odr_comparable (speculative_outer_type,
240410d565efSmrg 				 x.speculative_outer_type)
240510d565efSmrg 	  || !types_same_for_odr  (speculative_outer_type,
240610d565efSmrg 				   x.speculative_outer_type)
240710d565efSmrg 	  || speculative_offset != x.speculative_offset
240810d565efSmrg 	  || speculative_maybe_derived_type != x.speculative_maybe_derived_type)
240910d565efSmrg 	return false;
241010d565efSmrg     }
241110d565efSmrg   else if (x.speculative_outer_type
241210d565efSmrg 	   && x.speculation_consistent_p (x.speculative_outer_type,
241310d565efSmrg 					  x.speculative_offset,
241410d565efSmrg 				  	  x.speculative_maybe_derived_type,
241510d565efSmrg 					  NULL))
241610d565efSmrg     return false;
241710d565efSmrg 
241810d565efSmrg   return true;
241910d565efSmrg }
242010d565efSmrg 
242110d565efSmrg /* Modify context to be strictly less restrictive than CTX.  */
242210d565efSmrg 
242310d565efSmrg bool
meet_with(ipa_polymorphic_call_context ctx,tree otr_type)242410d565efSmrg ipa_polymorphic_call_context::meet_with (ipa_polymorphic_call_context ctx,
242510d565efSmrg 					 tree otr_type)
242610d565efSmrg {
242710d565efSmrg   bool updated = false;
242810d565efSmrg 
242910d565efSmrg   if (useless_p () || ctx.invalid)
243010d565efSmrg     return false;
243110d565efSmrg 
243210d565efSmrg   /* Restricting context to inner type makes merging easier, however do not
243310d565efSmrg      do that unless we know how the context is used (OTR_TYPE is non-NULL)  */
243410d565efSmrg   if (otr_type && !useless_p () && !ctx.useless_p ())
243510d565efSmrg     {
243610d565efSmrg       restrict_to_inner_class (otr_type);
243710d565efSmrg       ctx.restrict_to_inner_class (otr_type);
243810d565efSmrg       if(invalid)
243910d565efSmrg         return false;
244010d565efSmrg     }
244110d565efSmrg 
244210d565efSmrg   if (equal_to (ctx))
244310d565efSmrg     return false;
244410d565efSmrg 
244510d565efSmrg   if (ctx.useless_p () || invalid)
244610d565efSmrg     {
244710d565efSmrg       *this = ctx;
244810d565efSmrg       return true;
244910d565efSmrg     }
245010d565efSmrg 
245110d565efSmrg   if (dump_file && (dump_flags & TDF_DETAILS))
245210d565efSmrg     {
245310d565efSmrg       fprintf (dump_file, "Polymorphic call context meet:");
245410d565efSmrg       dump (dump_file);
245510d565efSmrg       fprintf (dump_file, "With context:                    ");
245610d565efSmrg       ctx.dump (dump_file);
245710d565efSmrg       if (otr_type)
245810d565efSmrg 	{
245910d565efSmrg           fprintf (dump_file, "To be used with type:            ");
246010d565efSmrg 	  print_generic_expr (dump_file, otr_type, TDF_SLIM);
246110d565efSmrg           fprintf (dump_file, "\n");
246210d565efSmrg 	}
246310d565efSmrg     }
246410d565efSmrg 
246510d565efSmrg   if (!dynamic && ctx.dynamic)
246610d565efSmrg     {
246710d565efSmrg       dynamic = true;
246810d565efSmrg       updated = true;
246910d565efSmrg     }
247010d565efSmrg 
247110d565efSmrg   /* If call is known to be invalid, we are done.  */
247210d565efSmrg   if (!outer_type)
247310d565efSmrg     ;
247410d565efSmrg   else if (!ctx.outer_type)
247510d565efSmrg     {
247610d565efSmrg       clear_outer_type ();
247710d565efSmrg       updated = true;
247810d565efSmrg     }
247910d565efSmrg   /* If types are known to be same, merging is quite easy.  */
248010d565efSmrg   else if (types_must_be_same_for_odr (outer_type, ctx.outer_type))
248110d565efSmrg     {
248210d565efSmrg       if (offset != ctx.offset
248310d565efSmrg 	  && TYPE_SIZE (outer_type)
248410d565efSmrg 	  && TREE_CODE (TYPE_SIZE (outer_type)) == INTEGER_CST)
248510d565efSmrg 	{
248610d565efSmrg 	  if (dump_file && (dump_flags & TDF_DETAILS))
248710d565efSmrg 	    fprintf (dump_file, "Outer types match, offset mismatch -> clearing\n");
248810d565efSmrg 	  clear_outer_type ();
248910d565efSmrg 	  return true;
249010d565efSmrg 	}
249110d565efSmrg       if (dump_file && (dump_flags & TDF_DETAILS))
249210d565efSmrg         fprintf (dump_file, "Outer types match, merging flags\n");
249310d565efSmrg       if (!maybe_in_construction && ctx.maybe_in_construction)
249410d565efSmrg 	{
249510d565efSmrg 	  updated = true;
249610d565efSmrg 	  maybe_in_construction = true;
249710d565efSmrg 	}
249810d565efSmrg       if (!maybe_derived_type && ctx.maybe_derived_type)
249910d565efSmrg 	{
250010d565efSmrg 	  updated = true;
250110d565efSmrg 	  maybe_derived_type = true;
250210d565efSmrg 	}
250310d565efSmrg       if (!dynamic && ctx.dynamic)
250410d565efSmrg 	{
250510d565efSmrg 	  updated = true;
250610d565efSmrg 	  dynamic = true;
250710d565efSmrg 	}
250810d565efSmrg     }
250910d565efSmrg   /* See if one type contains the other as a field (not base).  */
251010d565efSmrg   else if (contains_type_p (ctx.outer_type, ctx.offset - offset,
251110d565efSmrg 			    outer_type, false, false))
251210d565efSmrg     {
251310d565efSmrg       if (dump_file && (dump_flags & TDF_DETAILS))
251410d565efSmrg 	fprintf (dump_file, "Second type contain the first as a field\n");
251510d565efSmrg 
251610d565efSmrg       /* The second type is more specified, so we keep the first.
251710d565efSmrg          We need to set DYNAMIC flag to avoid declaring context INVALID
251810d565efSmrg 	 of OFFSET ends up being out of range.  */
251910d565efSmrg       if (!dynamic
252010d565efSmrg 	  && (ctx.dynamic
252110d565efSmrg 	      || (!otr_type
252210d565efSmrg 		  && (!TYPE_SIZE (ctx.outer_type)
252310d565efSmrg 		      || !TYPE_SIZE (outer_type)
252410d565efSmrg 		      || !operand_equal_p (TYPE_SIZE (ctx.outer_type),
252510d565efSmrg 					   TYPE_SIZE (outer_type), 0)))))
252610d565efSmrg 	{
252710d565efSmrg 	  dynamic = true;
252810d565efSmrg 	  updated = true;
252910d565efSmrg 	}
253010d565efSmrg     }
253110d565efSmrg   else if (contains_type_p (outer_type, offset - ctx.offset,
253210d565efSmrg 			    ctx.outer_type, false, false))
253310d565efSmrg     {
253410d565efSmrg       if (dump_file && (dump_flags & TDF_DETAILS))
253510d565efSmrg 	fprintf (dump_file, "First type contain the second as a field\n");
253610d565efSmrg 
253710d565efSmrg       if (!dynamic
253810d565efSmrg 	  && (ctx.dynamic
253910d565efSmrg 	      || (!otr_type
254010d565efSmrg 		  && (!TYPE_SIZE (ctx.outer_type)
254110d565efSmrg 		      || !TYPE_SIZE (outer_type)
254210d565efSmrg 		      || !operand_equal_p (TYPE_SIZE (ctx.outer_type),
254310d565efSmrg 					   TYPE_SIZE (outer_type), 0)))))
254410d565efSmrg 	dynamic = true;
254510d565efSmrg       outer_type = ctx.outer_type;
254610d565efSmrg       offset = ctx.offset;
254710d565efSmrg       dynamic = ctx.dynamic;
254810d565efSmrg       maybe_in_construction = ctx.maybe_in_construction;
254910d565efSmrg       maybe_derived_type = ctx.maybe_derived_type;
255010d565efSmrg       updated = true;
255110d565efSmrg     }
255210d565efSmrg   /* See if OUTER_TYPE is base of CTX.OUTER_TYPE.  */
255310d565efSmrg   else if (contains_type_p (ctx.outer_type,
255410d565efSmrg 			    ctx.offset - offset, outer_type, false, true))
255510d565efSmrg     {
255610d565efSmrg       if (dump_file && (dump_flags & TDF_DETAILS))
255710d565efSmrg 	fprintf (dump_file, "First type is base of second\n");
255810d565efSmrg       if (!maybe_derived_type)
255910d565efSmrg 	{
256010d565efSmrg 	  maybe_derived_type = true;
256110d565efSmrg 	  updated = true;
256210d565efSmrg 	}
256310d565efSmrg       if (!maybe_in_construction && ctx.maybe_in_construction)
256410d565efSmrg 	{
256510d565efSmrg 	  maybe_in_construction = true;
256610d565efSmrg 	  updated = true;
256710d565efSmrg 	}
256810d565efSmrg       if (!dynamic && ctx.dynamic)
256910d565efSmrg 	{
257010d565efSmrg 	  dynamic = true;
257110d565efSmrg 	  updated = true;
257210d565efSmrg 	}
257310d565efSmrg     }
257410d565efSmrg   /* See if CTX.OUTER_TYPE is base of OUTER_TYPE.  */
257510d565efSmrg   else if (contains_type_p (outer_type,
257610d565efSmrg 			    offset - ctx.offset, ctx.outer_type, false, true))
257710d565efSmrg     {
257810d565efSmrg       if (dump_file && (dump_flags & TDF_DETAILS))
257910d565efSmrg 	fprintf (dump_file, "Second type is base of first\n");
258010d565efSmrg       outer_type = ctx.outer_type;
258110d565efSmrg       offset = ctx.offset;
258210d565efSmrg       updated = true;
258310d565efSmrg       if (!maybe_derived_type)
258410d565efSmrg 	maybe_derived_type = true;
258510d565efSmrg       if (!maybe_in_construction && ctx.maybe_in_construction)
258610d565efSmrg 	maybe_in_construction = true;
258710d565efSmrg       if (!dynamic && ctx.dynamic)
258810d565efSmrg 	dynamic = true;
258910d565efSmrg     }
2590*ec02198aSmrg   /* TODO handle merging using hierarchy. */
259110d565efSmrg   else
259210d565efSmrg     {
259310d565efSmrg       if (dump_file && (dump_flags & TDF_DETAILS))
259410d565efSmrg         fprintf (dump_file, "Giving up on meet\n");
259510d565efSmrg       clear_outer_type ();
259610d565efSmrg       updated = true;
259710d565efSmrg     }
259810d565efSmrg 
259910d565efSmrg   updated |= meet_speculation_with (ctx.speculative_outer_type,
260010d565efSmrg 				    ctx.speculative_offset,
260110d565efSmrg 				    ctx.speculative_maybe_derived_type,
260210d565efSmrg 				    otr_type);
260310d565efSmrg 
260410d565efSmrg   if (updated && dump_file && (dump_flags & TDF_DETAILS))
260510d565efSmrg     {
260610d565efSmrg       fprintf (dump_file, "Updated as:                      ");
260710d565efSmrg       dump (dump_file);
260810d565efSmrg       fprintf (dump_file, "\n");
260910d565efSmrg     }
261010d565efSmrg   return updated;
261110d565efSmrg }
2612