Hi,
this patch adds basic tracking of what types may be in construction because the
call appears in a polymorphic cdtor.

Bootstrapped/regtested x86_64-linux, comitted.

Honza
        * cgraph.h (struct indirect_call_info): Add IN_POLYMORPHIC_CDTOR
        * lto-cgraph.c (lto_output_edge, input_edge): Stream
        in_polymorphic_cdtor
        * cgraph.c (symbol_table::create_edge): Compute in_polymorphic_cdtor.
        (cgraph_edge::make_speculative): Copy in_polymorphic_cdtor.
        * cgraphclones.c (cgraph_edge::clone): Likewise.
        * ipa-prop.c (update_jump_functions_after_inlining, 
        try_make_edge_direct_virtual_call): Pass in_polymorphic_cdtor
        to possible_dynamic_type_change.
        (decl_maybe_in_construction_p): Allow empty OUTER_TYPE and BASE.
        (ipa_polymorphic_call_context::possible_dynamic_type_change): Add
        IN_POLY_CDOTR argument.

Index: cgraph.h
===================================================================
--- cgraph.h    (revision 215870)
+++ cgraph.h    (working copy)
@@ -1333,7 +1333,7 @@ public:
   void offset_by (HOST_WIDE_INT);
   /* 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);
+  void possible_dynamic_type_change (bool, 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
@@ -1512,6 +1512,9 @@ struct GTY((chain_next ("%h.next_caller"
      Optimizers may later redirect direct call to clone, so 1) and 3)
      do not need to necesarily agree with destination.  */
   unsigned int speculative : 1;
+  /* Set to true when caller is a constructor or destructor of polymorphic
+     type.  */
+  unsigned in_polymorphic_cdtor : 1;
 
 private:
   /* Remove the edge from the list of the callers of the callee.  */
Index: lto-cgraph.c
===================================================================
--- lto-cgraph.c        (revision 215870)
+++ lto-cgraph.c        (working copy)
@@ -284,6 +284,7 @@ lto_output_edge (struct lto_simple_outpu
   bp_pack_value (&bp, edge->speculative, 1);
   bp_pack_value (&bp, edge->call_stmt_cannot_inline_p, 1);
   bp_pack_value (&bp, edge->can_throw_external, 1);
+  bp_pack_value (&bp, edge->in_polymorphic_cdtor, 1);
   if (edge->indirect_unknown_callee)
     {
       int flags = edge->indirect_info->ecf_flags;
@@ -1366,6 +1367,7 @@ input_edge (struct lto_input_block *ib,
   edge->inline_failed = inline_failed;
   edge->call_stmt_cannot_inline_p = bp_unpack_value (&bp, 1);
   edge->can_throw_external = bp_unpack_value (&bp, 1);
+  edge->in_polymorphic_cdtor = bp_unpack_value (&bp, 1);
   if (indirect)
     {
       if (bp_unpack_value (&bp, 1))
Index: cgraph.c
===================================================================
--- cgraph.c    (revision 215870)
+++ cgraph.c    (working copy)
@@ -819,6 +819,12 @@ symbol_table::create_edge (cgraph_node *
   edge->indirect_inlining_edge = 0;
   edge->speculative = false;
   edge->indirect_unknown_callee = indir_unknown_callee;
+  if (flag_devirtualize && call_stmt && DECL_STRUCT_FUNCTION (caller->decl))
+    edge->in_polymorphic_cdtor
+      = decl_maybe_in_construction_p (NULL, NULL, call_stmt,
+                                     caller->decl);
+  else
+    edge->in_polymorphic_cdtor = caller->thunk.thunk_p;
   if (call_stmt && caller->call_site_hash)
     cgraph_add_edge_to_call_site_hash (edge);
 
@@ -1033,6 +1039,7 @@ cgraph_edge::make_speculative (cgraph_no
   else
     e2->can_throw_external = can_throw_external;
   e2->lto_stmt_uid = lto_stmt_uid;
+  e2->in_polymorphic_cdtor = in_polymorphic_cdtor;
   count -= e2->count;
   frequency -= e2->frequency;
   symtab->call_edge_duplication_hooks (this, e2);
Index: cgraphclones.c
===================================================================
--- cgraphclones.c      (revision 215870)
+++ cgraphclones.c      (working copy)
@@ -159,6 +159,7 @@ cgraph_edge::clone (cgraph_node *n, gimp
   new_edge->can_throw_external = can_throw_external;
   new_edge->call_stmt_cannot_inline_p = call_stmt_cannot_inline_p;
   new_edge->speculative = speculative;
+  new_edge->in_polymorphic_cdtor = in_polymorphic_cdtor;
   if (update_original)
     {
       count -= new_edge->count;
Index: ipa-prop.c
===================================================================
--- ipa-prop.c  (revision 215870)
+++ 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.possible_dynamic_type_change ();
+               ctx.possible_dynamic_type_change (e->in_polymorphic_cdtor);
              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.possible_dynamic_type_change ();
+                   ctx.possible_dynamic_type_change (e->in_polymorphic_cdtor);
                  if (!ctx.useless_p ())
                    {
                      if (!dst_ctx)
@@ -3128,7 +3128,8 @@ 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.possible_dynamic_type_change (ie->indirect_info->otr_type);
+      ctx.possible_dynamic_type_change (ie->in_polymorphic_cdtor,
+                                       ie->indirect_info->otr_type);
 
       updated = ie->indirect_info->context.combine_with
                  (ctx, ie->indirect_info->otr_type);
Index: ipa-polymorphic-call.c
===================================================================
--- ipa-polymorphic-call.c      (revision 215870)
+++ ipa-polymorphic-call.c      (working copy)
@@ -475,6 +475,11 @@ contains_type_p (tree outer_type, HOST_W
    (not dynamically allocated) and we want to disprove the fact
    that it may be in construction at invocation of CALL.
 
+   BASE represents memory location where instance is stored.
+   If BASE is NULL, it is assumed to be global memory.
+   OUTER_TYPE is known type of the instance or NULL if not
+   known.
+
    For the variable to be in construction we actually need to
    be in constructor of corresponding global variable or
    the inline stack of CALL must contain the constructor.
@@ -486,8 +491,9 @@ bool
 decl_maybe_in_construction_p (tree base, tree outer_type,
                              gimple call, tree function)
 {
-  outer_type = TYPE_MAIN_VARIANT (outer_type);
-  gcc_assert (DECL_P (base));
+  if (outer_type)
+    outer_type = TYPE_MAIN_VARIANT (outer_type);
+  gcc_assert (!base || DECL_P (base));
 
   /* After inlining the code unification optimizations may invalidate
      inline stacks.  Also we need to give up on global variables after
@@ -498,7 +504,7 @@ decl_maybe_in_construction_p (tree base,
 
   /* Pure functions can not do any changes on the dynamic type;
      that require writting to memory.  */
-  if (!auto_var_in_fn_p (base, function)
+  if (base && !auto_var_in_fn_p (base, function)
       && flags_from_decl_or_type (function) & (ECF_PURE | ECF_CONST))
     return false;
 
@@ -517,7 +523,7 @@ decl_maybe_in_construction_p (tree base,
               argument (pointer to the instance).  */
            fn = DECL_ABSTRACT_ORIGIN (fn);
            if (!fn
-               || !is_global_var (base)
+               || (!base || !is_global_var (base))
                || TREE_CODE (TREE_TYPE (fn)) != METHOD_TYPE
                || (!DECL_CXX_CONSTRUCTOR_P (fn)
                    && !DECL_CXX_DESTRUCTOR_P (fn)))
@@ -526,17 +532,20 @@ decl_maybe_in_construction_p (tree base,
        if (flags_from_decl_or_type (fn) & (ECF_PURE | ECF_CONST))
          continue;
 
-       /* FIXME: this can go away once we have ODR types equivalency on
-          LTO level.  */
-       if (in_lto_p && !polymorphic_type_binfo_p (TYPE_BINFO (outer_type)))
-         return true;
        tree type = TYPE_MAIN_VARIANT (method_class_type (TREE_TYPE (fn)));
-       if (types_same_for_odr (type, outer_type))
+
+       if (!outer_type || !types_odr_comparable (type, outer_type))
+         {
+           if (TREE_CODE (type) == RECORD_TYPE
+               && TYPE_BINFO (type)
+               && polymorphic_type_binfo_p (TYPE_BINFO (type)))
+             return true;
+         }
+       else if (types_same_for_odr (type, outer_type))
          return true;
       }
 
-  if (TREE_CODE (base) == VAR_DECL
-      && is_global_var (base))
+  if (!base || (TREE_CODE (base) == VAR_DECL && is_global_var (base)))
     {
       if (TREE_CODE (TREE_TYPE (function)) != METHOD_TYPE
          || (!DECL_CXX_CONSTRUCTOR_P (function)
@@ -553,12 +562,15 @@ decl_maybe_in_construction_p (tree base,
                  && !DECL_CXX_DESTRUCTOR_P (function)))
            return false;
        }
-      /* FIXME: this can go away once we have ODR types equivalency on
-        LTO level.  */
-      if (in_lto_p && !polymorphic_type_binfo_p (TYPE_BINFO (outer_type)))
-       return true;
       tree type = TYPE_MAIN_VARIANT (method_class_type (TREE_TYPE (function)));
-      if (types_same_for_odr (type, outer_type))
+      if (!outer_type || !types_odr_comparable (type, outer_type))
+       {
+         if (TREE_CODE (type) == RECORD_TYPE
+             && TYPE_BINFO (type)
+             && polymorphic_type_binfo_p (TYPE_BINFO (type)))
+           return true;
+       }
+      else if (types_same_for_odr (type, outer_type))
        return true;
     }
   return false;
@@ -2009,10 +2021,11 @@ ipa_polymorphic_call_context::make_specu
    type change is not happening.  */
 
 void
-ipa_polymorphic_call_context::possible_dynamic_type_change (tree otr_type)
+ipa_polymorphic_call_context::possible_dynamic_type_change (bool in_poly_cdtor,
+                                                           tree otr_type)
 {
   if (dynamic)
     make_speculative (otr_type);
-  else
+  else if (in_poly_cdtor)
     maybe_in_construction = true;
 }

Reply via email to