diff mbox

Add dynamic flag into polymorphic call context

Message ID 20141003041654.GB21871@kam.mff.cuni.cz
State New
Headers show

Commit Message

Jan Hubicka Oct. 3, 2014, 4:16 a.m. UTC
Hi,
this patch adds very basic logic for tracking dynamic wrt static types.
Basically it intoruced field DYNAMIC that specify if context represent static
storage or type found by get_dynamic_type.  Static storage is stronger in a way
that we know its size (I do not track at all for dynamic types) and we make
assumption that user are not going to placement new it to completely different
data type (it is allowed to destroy it and re-construct by hand before it is destroyed
again at the end of static storage lifetime)

Bootstrapped/regtested x86_64-linux, will comit it shortly (after working out the
Ada bootstrap issue I caused).

Honza

	* cgraph.h (ipa_polymorphic_call_context):
	Turn bools into bitfields; add DYNAMIC; make MAKE_SPECULATIVE
	private, add POSSIBLE_DYNAMIC_TYPE_CHANGE.
	* ipa-polymorphic-call.c
	(ipa_polymorphic_call_context::restrict_to_inner_class): Allow accesses
	past end of dynamic types.
	(ipa_polymorphic_call_context::stream_out,
	speculative_outer_type): Stream dynamic flag.
	(ipa_polymorphic_call_context::set_by_decl): Clear DYNAMIC.
	(ipa_polymorphic_call_context::ipa_polymorphic_call_context):
	Clear DYNAMIC.
	(ipa_polymorphic_call_context::get_dynamic_type): Use DYNAMIC;
	set it.
	(ipa_polymorphic_call_context::combine_with): Propagate dynamic.
	* ipa-prop.c (update_jump_functions_after_inlining,
	try_make_edge_direct_virtual_call): Use possible_dynamic_type_change.
diff mbox

Patch

Index: cgraph.h
===================================================================
--- cgraph.h	(revision 215817)
+++ cgraph.h	(working copy)
@@ -1281,15 +1281,17 @@  public:
   tree outer_type;
   tree speculative_outer_type;
   /* True if outer object may be in construction or destruction.  */
-  bool maybe_in_construction;
+  unsigned maybe_in_construction : 1;
   /* True if outer object may be of derived type.  */
-  bool maybe_derived_type;
+  unsigned maybe_derived_type : 1;
   /* True if speculative outer object may be of derived type.  We always
      speculate that construction does not happen.  */
-  bool speculative_maybe_derived_type;
+  unsigned speculative_maybe_derived_type : 1;
   /* True if the context is invalid and all calls should be redirected
      to BUILTIN_UNREACHABLE.  */
-  bool invalid;
+  unsigned invalid : 1;
+  /* True if the outer type is dynamic.  */
+  unsigned dynamic : 1;
 
   /* Build empty "I know nothing" context.  */
   ipa_polymorphic_call_context ();
@@ -1329,12 +1331,9 @@  public:
 
   /* Adjust all offsets in contexts by given number of bits.  */
   void offset_by (HOST_WIDE_INT);
-  /* Take non-speculative info, merge it with speculative and clear speculatoin.
-     Used when we no longer manage to keep track of actual outer type, but we
-     think it is still there. 
-     If OTR_TYPE is set, the transformation can be done more effectively assuming
-     that context is going to be used only that way.  */
-  void make_speculative (tree otr_type = NULL);
+  /* Use when we can not track dynamic type change.  This speculatively assume
+     type change is not happening.  */
+  void possible_dynamic_type_change (tree otr_type = NULL);
   /* Assume that both THIS and a given context is valid and strenghten THIS
      if possible.  Return true if any strenghtening was made.
      If actual type the context is being used in is known, OTR_TYPE should be
@@ -1358,6 +1357,7 @@  private:
   bool set_by_invariant (tree, tree, HOST_WIDE_INT);
   void clear_outer_type (tree otr_type = NULL);
   bool speculation_consistent_p (tree, HOST_WIDE_INT, bool, tree);
+  void make_speculative (tree otr_type = NULL);
 };
 
 /* Structure containing additional information about an indirect call.  */
@@ -2662,6 +2662,7 @@  ipa_polymorphic_call_context::clear_oute
   offset = 0;
   maybe_derived_type = true;
   maybe_in_construction = true;
+  dynamic = true;
 }
 
 /* Adjust all offsets in contexts by OFF bits.  */
Index: ipa-polymorphic-call.c
===================================================================
--- ipa-polymorphic-call.c	(revision 215817)
+++ ipa-polymorphic-call.c	(working copy)
@@ -167,8 +167,11 @@  ipa_polymorphic_call_context::restrict_t
      type = otr_type;
      cur_offset = 0;
 
-     /* If derived type is not allowed, we know that the context is invalid.  */
-     if (!maybe_derived_type)
+     /* If derived type is not allowed, we know that the context is invalid.
+	For dynamic types, we really do not have information about
+	size of the memory location.  It is possible that completely
+	different type is stored after outer_type.  */
+     if (!maybe_derived_type && !dynamic)
        {
 	 clear_speculation ();
 	 invalid = true;
@@ -575,7 +578,7 @@  ipa_polymorphic_call_context::dump (FILE
 	fprintf (f, "nothing known");
       if (outer_type || offset)
 	{
-	  fprintf (f, "Outer type:");
+	  fprintf (f, "Outer type%s:", dynamic ? " (dynamic)":"");
 	  print_generic_expr (f, outer_type, TDF_SLIM);
 	  if (maybe_derived_type)
 	    fprintf (f, " (or a derived type)");
@@ -618,6 +621,7 @@  ipa_polymorphic_call_context::stream_out
   bp_pack_value (&bp, maybe_in_construction, 1);
   bp_pack_value (&bp, maybe_derived_type, 1);
   bp_pack_value (&bp, speculative_maybe_derived_type, 1);
+  bp_pack_value (&bp, dynamic, 1);
   bp_pack_value (&bp, outer_type != NULL, 1);
   bp_pack_value (&bp, offset != 0, 1);
   bp_pack_value (&bp, speculative_outer_type != NULL, 1);
@@ -648,6 +652,7 @@  ipa_polymorphic_call_context::stream_in
   maybe_in_construction = bp_unpack_value (&bp, 1);
   maybe_derived_type = bp_unpack_value (&bp, 1);
   speculative_maybe_derived_type = bp_unpack_value (&bp, 1);
+  dynamic = bp_unpack_value (&bp, 1);
   bool outer_type_p = bp_unpack_value (&bp, 1);
   bool offset_p = bp_unpack_value (&bp, 1);
   bool speculative_outer_type_p = bp_unpack_value (&bp, 1);
@@ -690,6 +695,7 @@  ipa_polymorphic_call_context::set_by_dec
      get_dynamic_type or decl_maybe_in_construction_p.  */
   maybe_in_construction = true;
   maybe_derived_type = false;
+  dynamic = false;
 }
 
 /* CST is an invariant (address of decl), try to get meaningful
@@ -889,6 +895,8 @@  ipa_polymorphic_call_context::ipa_polymo
 	      return;
 	    }
 
+	  dynamic = true;
+
 	  /* If the function is constructor or destructor, then
 	     the type is possibly in construction, but we know
 	     it is not derived type.  */
@@ -1192,6 +1200,7 @@  record_known_type (struct type_change_in
       context.outer_type = type;
       context.maybe_in_construction = false;
       context.maybe_derived_type = false;
+      context.dynamic = true;
       /* If we failed to find the inner type, we know that the call
 	 would be undefined for type produced here.  */
       if (!context.restrict_to_inner_class (tci->otr_type))
@@ -1540,6 +1549,7 @@  ipa_polymorphic_call_context::get_dynami
 
   if (!tci.type_maybe_changed
       || (outer_type
+	  && !dynamic
 	  && !tci.seen_unanalyzed_store
 	  && !tci.multiple_types_encountered
 	  && offset == tci.offset
@@ -1563,6 +1573,7 @@  ipa_polymorphic_call_context::get_dynami
 	{
 	  outer_type = TYPE_MAIN_VARIANT (tci.known_current_type);
 	  offset = tci.known_current_offset;
+	  dynamic = true;
 	  maybe_in_construction = false;
 	  maybe_derived_type = false;
 	  if (dump_file)
@@ -1792,6 +1803,7 @@  ipa_polymorphic_call_context::combine_wi
     {
       outer_type = ctx.outer_type;
       offset = ctx.offset;
+      dynamic = ctx.dynamic;
       maybe_in_construction = ctx.maybe_in_construction;
       maybe_derived_type = ctx.maybe_derived_type;
       updated = true;
@@ -1822,6 +1834,11 @@  ipa_polymorphic_call_context::combine_wi
 	  updated = true;
 	  maybe_derived_type = false;
 	}
+      if (dynamic && !ctx.dynamic)
+	{
+	  updated = true;
+	  dynamic = false;
+	}
     }
   /* If we know the type precisely, there is not much to improve.  */
   else if (!maybe_derived_type && !maybe_in_construction
@@ -1856,6 +1873,7 @@  ipa_polymorphic_call_context::combine_wi
 	  outer_type = ctx.outer_type;
 	  maybe_derived_type = ctx.maybe_derived_type;
 	  offset = ctx.offset;
+	  dynamic = ctx.dynamic;
 	  updated = true;
 	}
 
@@ -1906,6 +1924,7 @@  ipa_polymorphic_call_context::combine_wi
 	  maybe_in_construction = ctx.maybe_in_construction;
 	  maybe_derived_type = ctx.maybe_derived_type;
 	  offset = ctx.offset;
+	  dynamic = ctx.dynamic;
           updated = true;
 	}
     }
@@ -1952,7 +1971,10 @@  invalidate:
 
 /* Take non-speculative info, merge it with speculative and clear speculation.
    Used when we no longer manage to keep track of actual outer type, but we
-   think it is still there.  */
+   think it is still there.
+
+   If OTR_TYPE is set, the transformation can be done more effectively assuming
+   that context is going to be used only that way.  */
 
 void
 ipa_polymorphic_call_context::make_speculative (tree otr_type)
@@ -1975,3 +1997,15 @@  ipa_polymorphic_call_context::make_specu
 			    spec_maybe_derived_type,
 			    otr_type);
 }
+
+/* Use when we can not track dynamic type change.  This speculatively assume
+   type change is not happening.  */
+
+void
+ipa_polymorphic_call_context::possible_dynamic_type_change (tree otr_type)
+{
+  if (dynamic)
+    make_speculative (otr_type);
+  else
+    maybe_in_construction = true;
+}
Index: ipa-prop.c
===================================================================
--- ipa-prop.c	(revision 215817)
+++ ipa-prop.c	(working copy)
@@ -2652,7 +2652,7 @@  update_jump_functions_after_inlining (st
 
 	      /* TODO: Make type preserved safe WRT contexts.  */
 	      if (!dst->value.ancestor.agg_preserved)
-		ctx.make_speculative ();
+		ctx.possible_dynamic_type_change ();
 	      ctx.offset_by (dst->value.ancestor.offset);
 	      if (!ctx.useless_p ())
 		{
@@ -2722,7 +2722,7 @@  update_jump_functions_after_inlining (st
 
 		  /* TODO: Make type preserved safe WRT contexts.  */
 		  if (!dst->value.ancestor.agg_preserved)
-		    ctx.make_speculative ();
+		    ctx.possible_dynamic_type_change ();
 		  if (!ctx.useless_p ())
 		    {
 		      if (!dst_ctx)
@@ -3128,7 +3128,7 @@  try_make_edge_direct_virtual_call (struc
 
       /* TODO: We want to record if type change happens.  
 	 Old code did not do that that seems like a bug.  */
-      ctx.make_speculative (ie->indirect_info->otr_type);
+      ctx.possible_dynamic_type_change (ie->indirect_info->otr_type);
 
       updated = ie->indirect_info->context.combine_with
 		  (ctx, ie->indirect_info->otr_type);