Patchwork Create pass through and ancestor jump functions even there is dynamic type change

login
register
mail settings
Submitter Martin Jambor
Date Aug. 24, 2013, 2:55 p.m.
Message ID <20130824145536.GE32344@virgil.suse>
Download mbox | patch
Permalink /patch/269639/
State New
Headers show

Comments

Martin Jambor - Aug. 24, 2013, 2:55 p.m.
Hi,

the patch below does not punt when creating pass through and ancestor
jump functions when there is a possible dynamic type change detected
but rather clears a flag in those functions.  Indirect inlining and
IPA-CP then make sure they only propagate when the flag is set.

I have also merged one or two pieces of code in IPA-CP that did the
same so that I could change behavior at one place only and made
update_jump_functions_after_inlining slightly less ugly by not relying
on structure copying so much and constructing all but one jump
function types with the ipa_set_jf_* methods.  Hopefully that will
make the rather complicated function less error prone as it apparently
gets even more complex over time.

Bootstrapped and tested on x86_64-linux.  OK for trunk?

Thanks,

Martin


2013-08-23  Martin Jambor  <mjambor@suse.cz>

	* ipa-prop.h (ipa_pass_through_data): New field type_preserved.
	(ipa_ancestor_jf_data): Likewise.
	(ipa_get_jf_pass_through_agg_preserved): Fix comment typo.
	(ipa_get_jf_pass_through_type_preserved): New function.
	(ipa_get_jf_ancestor_agg_preserved): Fix comment typo.
	(ipa_get_jf_ancestor_type_preserved): New function.
	* ipa-cp.c (ipa_get_jf_pass_through_result): Honor type_preserved
	flag.
	(ipa_get_jf_ancestor_result): Likewise.
	(propagate_vals_accross_pass_through): Use
	ipa_get_jf_pass_through_result to do all the value mappings.
	* ipa-prop.c (ipa_print_node_jump_functions_for_edge): Dump the
	type_preserved flag.
	(ipa_set_jf_cst_copy): New function.
	(ipa_set_jf_simple_pass_through): Set the type_preserved flag.
	(ipa_set_jf_arith_pass_through): Likewise.
	(ipa_set_ancestor_jf): Likewise.
	(compute_complex_assign_jump_func): Set type_preserved instead of
	punting.
	(ipa_compute_jump_functions_for_edge): Likewise.
	(combine_known_type_and_ancestor_jfs): Honor type_preserved.
	(update_jump_functions_after_inlining): Update type_preserved.
	Explicitely create jump functions when combining one with
	pass_through.
	(ipa_write_jump_function): Stream the type_preserved flags.
	(ipa_read_jump_function): Likewise.
Jan Hubicka - Aug. 26, 2013, 10:12 a.m.
> 2013-08-23  Martin Jambor  <mjambor@suse.cz>
> 
> 	* ipa-prop.h (ipa_pass_through_data): New field type_preserved.
> 	(ipa_ancestor_jf_data): Likewise.
> 	(ipa_get_jf_pass_through_agg_preserved): Fix comment typo.
> 	(ipa_get_jf_pass_through_type_preserved): New function.
> 	(ipa_get_jf_ancestor_agg_preserved): Fix comment typo.
> 	(ipa_get_jf_ancestor_type_preserved): New function.
> 	* ipa-cp.c (ipa_get_jf_pass_through_result): Honor type_preserved
> 	flag.
> 	(ipa_get_jf_ancestor_result): Likewise.
> 	(propagate_vals_accross_pass_through): Use
> 	ipa_get_jf_pass_through_result to do all the value mappings.
> 	* ipa-prop.c (ipa_print_node_jump_functions_for_edge): Dump the
> 	type_preserved flag.
> 	(ipa_set_jf_cst_copy): New function.
> 	(ipa_set_jf_simple_pass_through): Set the type_preserved flag.
> 	(ipa_set_jf_arith_pass_through): Likewise.
> 	(ipa_set_ancestor_jf): Likewise.
> 	(compute_complex_assign_jump_func): Set type_preserved instead of
> 	punting.
> 	(ipa_compute_jump_functions_for_edge): Likewise.
> 	(combine_known_type_and_ancestor_jfs): Honor type_preserved.
> 	(update_jump_functions_after_inlining): Update type_preserved.
> 	Explicitely create jump functions when combining one with
> 	pass_through.
> 	(ipa_write_jump_function): Stream the type_preserved flags.
> 	(ipa_read_jump_function): Likewise.
> +  if (TREE_CODE (input) == TREE_BINFO)
> +    {
> +      if (ipa_get_jf_pass_through_type_preserved (jfunc))
> +	{
> +	  gcc_checking_assert (ipa_get_jf_pass_through_operation (jfunc)
> +			       == NOP_EXPR);
> +	  return input;
> +	}
> +      return NULL_TREE;
> +    }
To handle the types in construction well, I plan to extend
possible_polymorphic_call_targets to get an OUTER_TYPE, OFFSET, INCLUDE_BASES,
INCLUDE_DERIVED_TYPES arguments (in addition to existing OTR_TYPE and
OTR_TOKEN).  OUTER_TYPE and OFFSET is what we now pass into get_binfo_at_offset
(i.e. the dynamic type of object we can track and offset of our subobject we
have virtual call for), where INCLUDE_BASES if true will make it to record all
the mathcing virtual methods of basetypes of OTR_TYPE, while
INCLUDE_DERIVED_TYPES will make it to record all matchng virtual methods of
derived types of OUTER_TYPE. If both are NULL, it will do what
get_binfo_at_offset does currently.  Does it seem to work for you?

In the case you have !ipa_get_jf_pass_through_type_preserved, I believe you
will just set INCLUDE_BASES (since you do not know if outer_type is in
construction)

The INCLUDE_DERIVED_TYPES will be useful when we know the outer_object comes
from THIS pointer of a method that is not a constructor. I this case we know
that the type is either type of object the method is defined for or one of its
derivations.

Again if outer type is in construction (i.e. the method is constructor or
destructor) we will have both INCLUDE_DERIVED_TYPES and INCLUDE_BASES set.
The list will still be smaller than what we get now purely on the type of the
virtual call object.

Does this seem work for you?

the patch is OK,
thank you!
Honza

Patch

Index: src/gcc/ipa-cp.c
===================================================================
--- src.orig/gcc/ipa-cp.c	2013-08-22 11:49:25.000000000 +0200
+++ src/gcc/ipa-cp.c	2013-08-23 12:20:04.000000000 +0200
@@ -745,17 +745,26 @@  initialize_node_lattices (struct cgraph_
 
 /* Return the result of a (possibly arithmetic) pass through jump function
    JFUNC on the constant value INPUT.  Return NULL_TREE if that cannot be
-   determined or itself is considered an interprocedural invariant.  */
+   determined or be considered an interprocedural invariant.  */
 
 static tree
 ipa_get_jf_pass_through_result (struct ipa_jump_func *jfunc, tree input)
 {
   tree restype, res;
 
+  if (TREE_CODE (input) == TREE_BINFO)
+    {
+      if (ipa_get_jf_pass_through_type_preserved (jfunc))
+	{
+	  gcc_checking_assert (ipa_get_jf_pass_through_operation (jfunc)
+			       == NOP_EXPR);
+	  return input;
+	}
+      return NULL_TREE;
+    }
+
   if (ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR)
     return input;
-  else if (TREE_CODE (input) == TREE_BINFO)
-    return NULL_TREE;
 
   gcc_checking_assert (is_gimple_ip_invariant (input));
   if (TREE_CODE_CLASS (ipa_get_jf_pass_through_operation (jfunc))
@@ -779,9 +788,13 @@  static tree
 ipa_get_jf_ancestor_result (struct ipa_jump_func *jfunc, tree input)
 {
   if (TREE_CODE (input) == TREE_BINFO)
-    return get_binfo_at_offset (input,
-				ipa_get_jf_ancestor_offset (jfunc),
-				ipa_get_jf_ancestor_type (jfunc));
+    {
+      if (!ipa_get_jf_ancestor_type_preserved (jfunc))
+	return NULL;
+      return get_binfo_at_offset (input,
+				  ipa_get_jf_ancestor_offset (jfunc),
+				  ipa_get_jf_ancestor_type (jfunc));
+    }
   else if (TREE_CODE (input) == ADDR_EXPR)
     {
       tree t = TREE_OPERAND (input, 0);
@@ -1013,26 +1026,16 @@  propagate_vals_accross_pass_through (str
   struct ipcp_value *src_val;
   bool ret = false;
 
-  if (ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR)
-    for (src_val = src_lat->values; src_val; src_val = src_val->next)
-      ret |= add_scalar_value_to_lattice (dest_lat, src_val->value, cs,
-					  src_val, src_idx);
   /* Do not create new values when propagating within an SCC because if there
      are arithmetic functions with circular dependencies, there is infinite
      number of them and we would just make lattices bottom.  */
-  else if (edge_within_scc (cs))
+  if ((ipa_get_jf_pass_through_operation (jfunc) != NOP_EXPR)
+      and edge_within_scc (cs))
     ret = set_lattice_contains_variable (dest_lat);
   else
     for (src_val = src_lat->values; src_val; src_val = src_val->next)
       {
-	tree cstval = src_val->value;
-
-	if (TREE_CODE (cstval) == TREE_BINFO)
-	  {
-	    ret |= set_lattice_contains_variable (dest_lat);
-	    continue;
-	  }
-	cstval = ipa_get_jf_pass_through_result (jfunc, cstval);
+	tree cstval = ipa_get_jf_pass_through_result (jfunc, src_val->value);
 
 	if (cstval)
 	  ret |= add_scalar_value_to_lattice (dest_lat, cstval, cs, src_val,
Index: src/gcc/ipa-prop.c
===================================================================
--- src.orig/gcc/ipa-prop.c	2013-08-22 11:49:25.000000000 +0200
+++ src/gcc/ipa-prop.c	2013-08-23 12:04:13.000000000 +0200
@@ -257,6 +257,8 @@  ipa_print_node_jump_functions_for_edge (
 	    }
 	  if (jump_func->value.pass_through.agg_preserved)
 	    fprintf (f, ", agg_preserved");
+	  if (jump_func->value.pass_through.type_preserved)
+	    fprintf (f, ", type_preserved");
 	  fprintf (f, "\n");
 	}
       else if (type == IPA_JF_ANCESTOR)
@@ -268,6 +270,8 @@  ipa_print_node_jump_functions_for_edge (
 	  print_generic_expr (f, jump_func->value.ancestor.type, 0);
 	  if (jump_func->value.ancestor.agg_preserved)
 	    fprintf (f, ", agg_preserved");
+	  if (jump_func->value.ancestor.type_preserved)
+	    fprintf (f, ", type_preserved");
 	  fprintf (f, "\n");
 	}
 
@@ -373,6 +377,19 @@  ipa_set_jf_known_type (struct ipa_jump_f
   jfunc->value.known_type.component_type = component_type;
 }
 
+/* Set JFUNC to be a copy of another jmp (to be used by jump function
+   combination code).  The two functions will share their rdesc.  */
+
+static void
+ipa_set_jf_cst_copy (struct ipa_jump_func *dst,
+		     struct ipa_jump_func *src)
+
+{
+  gcc_checking_assert (src->type == IPA_JF_CONST);
+  dst->type = IPA_JF_CONST;
+  dst->value.constant = src->value.constant;
+}
+
 /* Set JFUNC to be a constant jmp function.  */
 
 static void
@@ -406,13 +423,14 @@  ipa_set_jf_constant (struct ipa_jump_fun
 /* Set JFUNC to be a simple pass-through jump function.  */
 static void
 ipa_set_jf_simple_pass_through (struct ipa_jump_func *jfunc, int formal_id,
-				bool agg_preserved)
+				bool agg_preserved, bool type_preserved)
 {
   jfunc->type = IPA_JF_PASS_THROUGH;
   jfunc->value.pass_through.operand = NULL_TREE;
   jfunc->value.pass_through.formal_id = formal_id;
   jfunc->value.pass_through.operation = NOP_EXPR;
   jfunc->value.pass_through.agg_preserved = agg_preserved;
+  jfunc->value.pass_through.type_preserved = type_preserved;
 }
 
 /* Set JFUNC to be an arithmetic pass through jump function.  */
@@ -426,19 +444,22 @@  ipa_set_jf_arith_pass_through (struct ip
   jfunc->value.pass_through.formal_id = formal_id;
   jfunc->value.pass_through.operation = operation;
   jfunc->value.pass_through.agg_preserved = false;
+  jfunc->value.pass_through.type_preserved = false;
 }
 
 /* Set JFUNC to be an ancestor jump function.  */
 
 static void
 ipa_set_ancestor_jf (struct ipa_jump_func *jfunc, HOST_WIDE_INT offset,
-		     tree type, int formal_id, bool agg_preserved)
+		     tree type, int formal_id, bool agg_preserved,
+		     bool type_preserved)
 {
   jfunc->type = IPA_JF_ANCESTOR;
   jfunc->value.ancestor.formal_id = formal_id;
   jfunc->value.ancestor.offset = offset;
   jfunc->value.ancestor.type = type;
   jfunc->value.ancestor.agg_preserved = agg_preserved;
+  jfunc->value.ancestor.type_preserved = type_preserved;
 }
 
 /* Extract the acual BINFO being described by JFUNC which must be a known type
@@ -1005,12 +1026,13 @@  compute_complex_assign_jump_func (struct
 	  ipa_set_jf_arith_pass_through (jfunc, index, op2,
 					 gimple_assign_rhs_code (stmt));
 	}
-      else if (gimple_assign_single_p (stmt)
-	       && !detect_type_change_ssa (tc_ssa, call, jfunc))
+      else if (gimple_assign_single_p (stmt))
 	{
 	  bool agg_p = parm_ref_data_pass_through_p (&parms_ainfo[index],
 						     call, tc_ssa);
-	  ipa_set_jf_simple_pass_through (jfunc, index, agg_p);
+	  bool type_p = !detect_type_change_ssa (tc_ssa, call, jfunc);
+	  if (type_p || jfunc->type == IPA_JF_UNKNOWN)
+	    ipa_set_jf_simple_pass_through (jfunc, index, agg_p, type_p);
 	}
       return;
     }
@@ -1033,13 +1055,16 @@  compute_complex_assign_jump_func (struct
       || offset < 0)
     return;
 
-  /* Dynamic types are changed only in constructors and destructors and  */
+  /* Dynamic types are changed in constructors and destructors.  */
   index = ipa_get_param_decl_index (info, SSA_NAME_VAR (ssa));
-  if (index >= 0
-      && !detect_type_change (op1, base, call, jfunc, offset))
-    ipa_set_ancestor_jf (jfunc, offset, TREE_TYPE (op1), index,
-			 parm_ref_data_pass_through_p (&parms_ainfo[index],
-						       call, ssa));
+  if (index >= 0)
+    {
+      bool type_p = !detect_type_change (op1, base, call, jfunc, offset);
+      if (type_p || jfunc->type == IPA_JF_UNKNOWN)
+	ipa_set_ancestor_jf (jfunc, offset, TREE_TYPE (op1), index,
+			     parm_ref_data_pass_through_p (&parms_ainfo[index],
+							   call, ssa), type_p);
+    }
 }
 
 /* Extract the base, offset and MEM_REF expression from a statement ASSIGN if
@@ -1163,10 +1188,11 @@  compute_complex_ancestor_jump_func (stru
 	return;
     }
 
-  if (!detect_type_change (obj, expr, call, jfunc, offset))
+  bool type_p = !detect_type_change (obj, expr, call, jfunc, offset);
+  if (type_p || jfunc->type == IPA_JF_UNKNOWN)
     ipa_set_ancestor_jf (jfunc, offset, TREE_TYPE (obj), index,
 			 parm_ref_data_pass_through_p (&parms_ainfo[index],
-						       call, parm));
+						       call, parm), type_p);
 }
 
 /* Given OP which is passed as an actual argument to a called function,
@@ -1507,7 +1533,7 @@  ipa_compute_jump_functions_for_edge (str
 	     for cycle.  */
 	  if (parm_preserved_before_stmt_p (&parms_ainfo[index], call, arg))
 	    {
-	      ipa_set_jf_simple_pass_through (jfunc, index, false);
+	      ipa_set_jf_simple_pass_through (jfunc, index, false, false);
 	      continue;
 	    }
 	}
@@ -1516,13 +1542,14 @@  ipa_compute_jump_functions_for_edge (str
 	  if (SSA_NAME_IS_DEFAULT_DEF (arg))
 	    {
 	      int index = ipa_get_param_decl_index (info, SSA_NAME_VAR (arg));
-	      if (index >= 0
-		  && !detect_type_change_ssa (arg, call, jfunc))
+	      if (index >= 0)
 		{
-		  bool agg_p;
+		  bool agg_p, type_p;
 		  agg_p = parm_ref_data_pass_through_p (&parms_ainfo[index],
 							call, arg);
-		  ipa_set_jf_simple_pass_through (jfunc, index, agg_p);
+		  type_p = !detect_type_change_ssa (arg, call, jfunc);
+		  if (type_p || jfunc->type == IPA_JF_UNKNOWN)
+		    ipa_set_jf_simple_pass_through (jfunc, index, agg_p,						    type_p);
 		}
 	    }
 	  else
@@ -2130,6 +2157,12 @@  combine_known_type_and_ancestor_jfs (str
   HOST_WIDE_INT combined_offset;
   tree combined_type;
 
+  if (!ipa_get_jf_ancestor_type_preserved (dst))
+    {
+      dst->type = IPA_JF_UNKNOWN;
+      return;
+    }
+
   combined_offset = ipa_get_jf_known_type_offset (src)
     + ipa_get_jf_ancestor_offset (dst);
   combined_type = ipa_get_jf_ancestor_type (dst);
@@ -2196,6 +2229,8 @@  update_jump_functions_after_inlining (st
 	      dst->value.ancestor.formal_id = src->value.pass_through.formal_id;
 	      dst->value.ancestor.agg_preserved &=
 		src->value.pass_through.agg_preserved;
+	      dst->value.ancestor.type_preserved &=
+		src->value.pass_through.type_preserved;
 	    }
 	  else if (src->type == IPA_JF_ANCESTOR)
 	    {
@@ -2203,6 +2238,8 @@  update_jump_functions_after_inlining (st
 	      dst->value.ancestor.offset += src->value.ancestor.offset;
 	      dst->value.ancestor.agg_preserved &=
 		src->value.ancestor.agg_preserved;
+	      dst->value.ancestor.type_preserved &=
+		src->value.ancestor.type_preserved;
 	    }
 	  else
 	    dst->type = IPA_JF_UNKNOWN;
@@ -2216,16 +2253,69 @@  update_jump_functions_after_inlining (st
 	      && (dst->value.pass_through.formal_id
 		  < ipa_get_cs_argument_count (top)))
 	    {
-	      bool agg_p;
 	      int dst_fid = dst->value.pass_through.formal_id;
 	      src = ipa_get_ith_jump_func (top, dst_fid);
-	      agg_p = dst->value.pass_through.agg_preserved;
+	      bool dst_agg_p = ipa_get_jf_pass_through_agg_preserved (dst);
 
-	      dst->type = src->type;
-	      dst->value = src->value;
+	      switch (src->type)
+		{
+		case IPA_JF_UNKNOWN:
+		  dst->type = IPA_JF_UNKNOWN;
+		  break;
+		case IPA_JF_KNOWN_TYPE:
+		  ipa_set_jf_known_type (dst,
+					 ipa_get_jf_known_type_offset (src),
+					 ipa_get_jf_known_type_base_type (src),
+					 ipa_get_jf_known_type_base_type (src));
+		  break;
+		case IPA_JF_CONST:
+		  ipa_set_jf_cst_copy (dst, src);
+		  break;
+
+		case IPA_JF_PASS_THROUGH:
+		  {
+		    int formal_id = ipa_get_jf_pass_through_formal_id (src);
+		    enum tree_code operation;
+		    operation = ipa_get_jf_pass_through_operation (src);
+
+		    if (operation == NOP_EXPR)
+		      {
+			bool agg_p, type_p;
+			agg_p = dst_agg_p
+			  && ipa_get_jf_pass_through_agg_preserved (src);
+			type_p = ipa_get_jf_pass_through_type_preserved (src)
+			  && ipa_get_jf_pass_through_type_preserved (dst);
+			ipa_set_jf_simple_pass_through (dst, formal_id,
+							agg_p, type_p);
+		      }
+		    else
+		      {
+			tree operand = ipa_get_jf_pass_through_operand (src);
+			ipa_set_jf_arith_pass_through (dst, formal_id, operand,
+						       operation);
+		      }
+		    break;
+		  }
+		case IPA_JF_ANCESTOR:
+		  {
+		    bool agg_p, type_p;
+		    agg_p = dst_agg_p
+		      && ipa_get_jf_ancestor_agg_preserved (src);
+		    type_p = ipa_get_jf_ancestor_type_preserved (src)
+		      && ipa_get_jf_pass_through_type_preserved (dst);
+		    ipa_set_ancestor_jf (dst,
+					 ipa_get_jf_ancestor_offset (src),
+					 ipa_get_jf_ancestor_type (src),
+					 ipa_get_jf_ancestor_formal_id (src),
+					 agg_p, type_p);
+		    break;
+		  }
+		default:
+		  gcc_unreachable ();
+		}
 
 	      if (src->agg.items
-		  && (agg_p || !src->agg.by_ref))
+		  && (dst_agg_p || !src->agg.by_ref))
 		{
 		  /* Currently we do not produce clobber aggregate jump
 		     functions, replace with merging when we do.  */
@@ -2234,14 +2324,6 @@  update_jump_functions_after_inlining (st
 		  dst->agg.by_ref = src->agg.by_ref;
 		  dst->agg.items = vec_safe_copy (src->agg.items);
 		}
-
-	      if (!agg_p)
-		{
-		  if (dst->type == IPA_JF_PASS_THROUGH)
-		    dst->value.pass_through.agg_preserved = false;
-		  else if (dst->type == IPA_JF_ANCESTOR)
-		    dst->value.ancestor.agg_preserved = false;
-		}
 	    }
 	  else
 	    dst->type = IPA_JF_UNKNOWN;
@@ -3709,6 +3791,7 @@  ipa_write_jump_function (struct output_b
 	  streamer_write_uhwi (ob, jump_func->value.pass_through.formal_id);
 	  bp = bitpack_create (ob->main_stream);
 	  bp_pack_value (&bp, jump_func->value.pass_through.agg_preserved, 1);
+	  bp_pack_value (&bp, jump_func->value.pass_through.type_preserved, 1);
 	  streamer_write_bitpack (&bp);
 	}
       else
@@ -3723,6 +3806,7 @@  ipa_write_jump_function (struct output_b
       streamer_write_uhwi (ob, jump_func->value.ancestor.formal_id);
       bp = bitpack_create (ob->main_stream);
       bp_pack_value (&bp, jump_func->value.ancestor.agg_preserved, 1);
+      bp_pack_value (&bp, jump_func->value.ancestor.type_preserved, 1);
       streamer_write_bitpack (&bp);
       break;
     }
@@ -3780,7 +3864,9 @@  ipa_read_jump_function (struct lto_input
 	  int formal_id =  streamer_read_uhwi (ib);
 	  struct bitpack_d bp = streamer_read_bitpack (ib);
 	  bool agg_preserved = bp_unpack_value (&bp, 1);
-	  ipa_set_jf_simple_pass_through (jump_func, formal_id, agg_preserved);
+	  bool type_preserved = bp_unpack_value (&bp, 1);
+	  ipa_set_jf_simple_pass_through (jump_func, formal_id, agg_preserved,
+					  type_preserved);
 	}
       else
 	{
@@ -3797,8 +3883,10 @@  ipa_read_jump_function (struct lto_input
 	int formal_id = streamer_read_uhwi (ib);
 	struct bitpack_d bp = streamer_read_bitpack (ib);
 	bool agg_preserved = bp_unpack_value (&bp, 1);
+	bool type_preserved = bp_unpack_value (&bp, 1);
 
-	ipa_set_ancestor_jf (jump_func, offset, type, formal_id, agg_preserved);
+	ipa_set_ancestor_jf (jump_func, offset, type, formal_id, agg_preserved,
+			     type_preserved);
 	break;
       }
     }
Index: src/gcc/ipa-prop.h
===================================================================
--- src.orig/gcc/ipa-prop.h	2013-08-13 19:23:27.000000000 +0200
+++ src/gcc/ipa-prop.h	2013-08-22 13:51:04.000000000 +0200
@@ -117,7 +117,12 @@  struct GTY(()) ipa_pass_through_data
      aggregate part of the jump function (see description of
      ipa_agg_jump_function).  The flag is used only when the operation is
      NOP_EXPR.  */
-  bool agg_preserved;
+  unsigned agg_preserved : 1;
+
+  /* When set to true, we guarantee that, if there is a C++ object pointed to
+     by this object, it does not undergo dynamic type change in the course of
+     functions decribed by this jump function.  */
+  unsigned type_preserved : 1;
 };
 
 /* Structure holding data required to describe an ancestor pass-through
@@ -132,7 +137,11 @@  struct GTY(()) ipa_ancestor_jf_data
   /* Number of the caller's formal parameter being passed.  */
   int formal_id;
   /* Flag with the same meaning like agg_preserve in ipa_pass_through_data.  */
-  bool agg_preserved;
+  unsigned agg_preserved : 1;
+  /* When set to true, we guarantee that, if there is a C++ object pointed to
+     by this object, it does not undergo dynamic type change in the course of
+     functions decribed by this jump function.  */
+  unsigned type_preserved : 1;
 };
 
 /* An element in an aggegate part of a jump function describing a known value
@@ -264,7 +273,7 @@  ipa_get_jf_pass_through_operation (struc
   return jfunc->value.pass_through.operation;
 }
 
-/* Return the agg_preserved flag of a pass through jump functin JFUNC.  */
+/* Return the agg_preserved flag of a pass through jump function JFUNC.  */
 
 static inline bool
 ipa_get_jf_pass_through_agg_preserved (struct ipa_jump_func *jfunc)
@@ -273,6 +282,15 @@  ipa_get_jf_pass_through_agg_preserved (s
   return jfunc->value.pass_through.agg_preserved;
 }
 
+/* Return the type_preserved flag of a pass through jump function JFUNC.  */
+
+static inline bool
+ipa_get_jf_pass_through_type_preserved (struct ipa_jump_func *jfunc)
+{
+  gcc_checking_assert (jfunc->type == IPA_JF_PASS_THROUGH);
+  return jfunc->value.pass_through.type_preserved;
+}
+
 /* Return the offset of an ancestor jump function JFUNC.  */
 
 static inline HOST_WIDE_INT
@@ -301,7 +319,7 @@  ipa_get_jf_ancestor_formal_id (struct ip
   return jfunc->value.ancestor.formal_id;
 }
 
-/* Return the agg_preserved flag of an ancestor jump functin JFUNC.  */
+/* Return the agg_preserved flag of an ancestor jump function JFUNC.  */
 
 static inline bool
 ipa_get_jf_ancestor_agg_preserved (struct ipa_jump_func *jfunc)
@@ -310,6 +328,15 @@  ipa_get_jf_ancestor_agg_preserved (struc
   return jfunc->value.ancestor.agg_preserved;
 }
 
+/* Return the type_preserved flag of an ancestor jump function JFUNC.  */
+
+static inline bool
+ipa_get_jf_ancestor_type_preserved (struct ipa_jump_func *jfunc)
+{
+  gcc_checking_assert (jfunc->type == IPA_JF_ANCESTOR);
+  return jfunc->value.ancestor.type_preserved;
+}
+
 /* Summary describing a single formal parameter.  */
 
 struct ipa_param_descriptor