]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
* ipa-utils.h (ipa_polymorphic_call_context): Turn into class; add ctors.
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 20 Sep 2014 06:22:58 +0000 (06:22 +0000)
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 20 Sep 2014 06:22:58 +0000 (06:22 +0000)
(possible_polymorphic_call_targets, dump_possible_polymorphic_call_targets,
possible_polymorphic_call_target_p, possible_polymorphic_call_target_p): Simplify.
(get_dynamic_type): Remove.
* ipa-devirt.c (ipa_dummy_polymorphic_call_context): Remove.
(clear_speculation): Bring to ipa-deivrt.h
(get_class_context): Rename to ...
(ipa_polymorphic_call_context::restrict_to_inner_class): ... this one.
(contains_type_p): Update.
(get_dynamic_type): Rename to ...
ipa_polymorphic_call_context::get_dynamic_type(): ... this one.
(possible_polymorphic_call_targets): UPdate.
* tree-ssa-pre.c (eliminate_dom_walker::before_dom_children): Update.
* ipa-prop.c (ipa_analyze_call_uses): Update.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@215418 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/cgraph.c
gcc/gimple-fold.c
gcc/ipa-cp.c
gcc/ipa-devirt.c
gcc/ipa-prop.c
gcc/ipa-utils.h
gcc/tree-ssa-pre.c

index 87907fdd6fdf30a5c454fd12c444fa1915b4ca9b..87b5e00c50fc806e885eaf4502a626d38d4501f3 100644 (file)
@@ -1,3 +1,20 @@
+2014-09-19  Jan Hubicka  <hubicka@ucw.cz>
+
+       * ipa-utils.h (ipa_polymorphic_call_context): Turn into class; add ctors.
+       (possible_polymorphic_call_targets, dump_possible_polymorphic_call_targets,
+       possible_polymorphic_call_target_p, possible_polymorphic_call_target_p): Simplify.
+       (get_dynamic_type): Remove.
+       * ipa-devirt.c (ipa_dummy_polymorphic_call_context): Remove.
+       (clear_speculation): Bring to ipa-deivrt.h
+       (get_class_context): Rename to ...
+       (ipa_polymorphic_call_context::restrict_to_inner_class): ... this one.
+       (contains_type_p): Update.
+       (get_dynamic_type): Rename to ...
+       ipa_polymorphic_call_context::get_dynamic_type(): ... this one.
+       (possible_polymorphic_call_targets): UPdate.
+       * tree-ssa-pre.c (eliminate_dom_walker::before_dom_children): Update.
+       * ipa-prop.c (ipa_analyze_call_uses): Update.
+
 2014-09-19  Jan Hubicka  <hubicka@ucw.cz>
 
        * ipa-visibility.c (varpool_node::externally_visible_p): Do not
index 99e00764c80ed85075648851a524ccb7c23e5109..8f04284863f5c509788c9478870502d69cce5291 100644 (file)
@@ -884,21 +884,15 @@ cgraph_node::create_indirect_edge (gimple call_stmt, int ecf_flags,
       && (target = gimple_call_fn (call_stmt))
       && virtual_method_call_p (target))
     {
-      tree otr_type;
-      HOST_WIDE_INT otr_token;
-      ipa_polymorphic_call_context context;
-
-      get_polymorphic_call_info (decl,
-                                target,
-                                &otr_type, &otr_token,
-                                &context, call_stmt);
+      ipa_polymorphic_call_context context (decl, target, call_stmt);
 
       /* Only record types can have virtual calls.  */
-      gcc_assert (TREE_CODE (otr_type) == RECORD_TYPE);
       edge->indirect_info->polymorphic = true;
       edge->indirect_info->param_index = -1;
-      edge->indirect_info->otr_token = otr_token;
-      edge->indirect_info->otr_type = otr_type;
+      edge->indirect_info->otr_token
+        = tree_to_uhwi (OBJ_TYPE_REF_TOKEN (target));
+      edge->indirect_info->otr_type = obj_type_ref_class (target);
+      gcc_assert (TREE_CODE (edge->indirect_info->otr_type) == RECORD_TYPE);
       edge->indirect_info->outer_type = context.outer_type;
       edge->indirect_info->speculative_outer_type
         = context.speculative_outer_type;
index 3d5e3b91c040cba00b131c6f9a4dade742c23b36..dc2c9428893303823c58afb1f3f3dd9cfeae3068 100644 (file)
@@ -2563,8 +2563,8 @@ gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace)
        {
           if (dump_file && virtual_method_call_p (callee)
              && !possible_polymorphic_call_target_p
-                   (callee, cgraph_node::get (gimple_call_addr_fndecl
-                                              (OBJ_TYPE_REF_EXPR (callee)))))
+                   (callee, stmt, cgraph_node::get (gimple_call_addr_fndecl
+                                                    (OBJ_TYPE_REF_EXPR (callee)))))
            {
              fprintf (dump_file,
                       "Type inheritance inconsistent devirtualization of ");
index d36563490160d1940ae20e419078627b74aff828..2ff3b9c1e369f7bb5e519f04227ff7cc5c10c042 100644 (file)
@@ -1618,14 +1618,11 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
 
   if (TREE_CODE (t) != TREE_BINFO)
     {
-      ipa_polymorphic_call_context context;
+      ipa_polymorphic_call_context context (t, ie->indirect_info->otr_type,
+                                           anc_offset);
       vec <cgraph_node *>targets;
       bool final;
 
-      if (!get_polymorphic_call_info_from_invariant
-            (&context, t, ie->indirect_info->otr_type,
-             anc_offset))
-       return NULL_TREE;
       targets = possible_polymorphic_call_targets
                 (ie->indirect_info->otr_type,
                  ie->indirect_info->otr_token,
index 774275b22690ecdc223328e27c66dc730b6066b9..af42c6d6bffd925df320181751d587e5c094941c 100644 (file)
@@ -2400,41 +2400,43 @@ decl_maybe_in_construction_p (tree base, tree outer_type,
 }
 
 /* Proudce polymorphic call context for call method of instance
-   that is located within BASE (that is assumed to be a decl) at OFFSET. */
+   that is located within BASE (that is assumed to be a decl) at offset OFF. */
 
-static void
-get_polymorphic_call_info_for_decl (ipa_polymorphic_call_context *context,
-                                   tree base, HOST_WIDE_INT offset)
+void
+ipa_polymorphic_call_context::set_by_decl (tree base, HOST_WIDE_INT off)
 {
   gcc_assert (DECL_P (base));
 
-  context->outer_type = TYPE_MAIN_VARIANT (TREE_TYPE (base));
-  context->offset = offset;
-  context->speculative_outer_type = NULL;
-  context->speculative_offset = 0;
-  context->speculative_maybe_derived_type = true;
+  outer_type = TYPE_MAIN_VARIANT (TREE_TYPE (base));
+  offset = off;
+  clear_speculation ();
   /* Make very conservative assumption that all objects
      may be in construction. 
      TODO: ipa-prop already contains code to tell better. 
      merge it later.  */
-  context->maybe_in_construction = true;
-  context->maybe_derived_type = false;
+  maybe_in_construction = true;
+  maybe_derived_type = false;
 }
 
 /* CST is an invariant (address of decl), try to get meaningful
    polymorphic call context for polymorphic call of method 
-   if instance of OTR_TYPE that is located at OFFSET of this invariant.
+   if instance of OTR_TYPE that is located at offset OFF of this invariant.
    Return FALSE if nothing meaningful can be found.  */
 
 bool
-get_polymorphic_call_info_from_invariant (ipa_polymorphic_call_context *context,
-                                         tree cst,
-                                         tree otr_type,
-                                         HOST_WIDE_INT offset)
+ipa_polymorphic_call_context::set_by_invariant (tree cst,
+                                               tree otr_type,
+                                               HOST_WIDE_INT off)
 {
   HOST_WIDE_INT offset2, size, max_size;
   tree base;
 
+  invalid = false;
+  off = 0;
+  outer_type = NULL;
+  maybe_in_construction = true;
+  maybe_derived_type = true;
+
   if (TREE_CODE (cst) != ADDR_EXPR)
     return false;
 
@@ -2445,10 +2447,13 @@ get_polymorphic_call_info_from_invariant (ipa_polymorphic_call_context *context,
 
   /* Only type inconsistent programs can have otr_type that is
      not part of outer type.  */
-  if (!contains_type_p (TREE_TYPE (base), offset, otr_type))
-    return false;
+  if (otr_type && !contains_type_p (TREE_TYPE (base), off, otr_type))
+    {
+      invalid = true;
+      return false;
+    }
 
-  get_polymorphic_call_info_for_decl (context, base, offset);
+  set_by_decl (base, off);
   return true;
 }
 
@@ -2472,34 +2477,46 @@ walk_ssa_copies (tree op)
   return op;
 }
 
-/* Given REF call in FNDECL, determine class of the polymorphic
-   call (OTR_TYPE), its token (OTR_TOKEN) and CONTEXT.
-   CALL is optional argument giving the actual statement (usually call) where
-   the context is used.
-   Return pointer to object described by the context or an declaration if
-   we found the instance to be stored in the static storage.  */
+/* Create polymorphic call context from IP invariant CST.
+   This is typically &global_var.
+   OTR_TYPE specify type of polymorphic call or NULL if unknown, OFF
+   is offset of call.  */
 
-tree
-get_polymorphic_call_info (tree fndecl,
-                          tree ref,
-                          tree *otr_type,
-                          HOST_WIDE_INT *otr_token,
-                          ipa_polymorphic_call_context *context,
-                          gimple call)
+ipa_polymorphic_call_context::ipa_polymorphic_call_context (tree cst,
+                                                           tree otr_type,
+                                                           HOST_WIDE_INT off)
+{
+  clear_speculation ();
+  set_by_invariant (cst, otr_type, off);
+}
+
+/* Build context for pointer REF contained in FNDECL at statement STMT.
+   if INSTANCE is non-NULL, return pointer to the object described by
+   the context or DECL where context is contained in.  */
+
+ipa_polymorphic_call_context::ipa_polymorphic_call_context (tree fndecl,
+                                                           tree ref,
+                                                           gimple stmt,
+                                                           tree *instance)
 {
+  tree otr_type = NULL;
   tree base_pointer;
-  *otr_type = obj_type_ref_class (ref);
-  *otr_token = tree_to_uhwi (OBJ_TYPE_REF_TOKEN (ref));
+
+  if (TREE_CODE (ref) == OBJ_TYPE_REF)
+    {
+      otr_type = obj_type_ref_class (ref);
+      base_pointer = OBJ_TYPE_REF_OBJECT (ref);
+    }
+  else
+    base_pointer = ref;
 
   /* Set up basic info in case we find nothing interesting in the analysis.  */
-  context->speculative_outer_type = NULL;
-  context->speculative_offset = 0;
-  context->speculative_maybe_derived_type = true;
-  context->outer_type = TYPE_MAIN_VARIANT (*otr_type);
-  context->offset = 0;
-  base_pointer = OBJ_TYPE_REF_OBJECT (ref);
-  context->maybe_derived_type = true;
-  context->maybe_in_construction = true;
+  clear_speculation ();
+  outer_type = TYPE_MAIN_VARIANT (otr_type);
+  offset = 0;
+  maybe_derived_type = true;
+  maybe_in_construction = true;
+  invalid = false;
 
   /* Walk SSA for outer object.  */
   do 
@@ -2522,9 +2539,9 @@ get_polymorphic_call_info (tree fndecl,
              if (TREE_CODE (base) == MEM_REF)
                {
                  base_pointer = TREE_OPERAND (base, 0);
-                 context->offset
+                 offset
                    += offset2 + mem_ref_offset (base).to_short_addr () * BITS_PER_UNIT;
-                 context->outer_type = NULL;
+                 outer_type = NULL;
                }
              /* We found base object.  In this case the outer_type
                 is known.  */
@@ -2534,24 +2551,25 @@ get_polymorphic_call_info (tree fndecl,
 
                  /* Only type inconsistent programs can have otr_type that is
                     not part of outer type.  */
-                 if (!contains_type_p (TREE_TYPE (base),
-                                       context->offset + offset2, *otr_type))
+                 if (otr_type
+                     && !contains_type_p (TREE_TYPE (base),
+                                          offset + offset2, otr_type))
                    {
-                     /* Use OTR_TOKEN = INT_MAX as a marker of probably type inconsistent
-                        code sequences; we arrange the calls to be builtin_unreachable
-                        later.  */
-                     *otr_token = INT_MAX;
-                     return base_pointer;
+                     invalid = true;
+                     if (instance)
+                       *instance = base_pointer;
+                     return;
                    }
-                 get_polymorphic_call_info_for_decl (context, base,
-                                                     context->offset + offset2);
-                 if (context->maybe_in_construction && call)
-                   context->maybe_in_construction
+                 set_by_decl (base, offset + offset2);
+                 if (maybe_in_construction && stmt)
+                   maybe_in_construction
                     = decl_maybe_in_construction_p (base,
-                                                    context->outer_type,
-                                                    call,
+                                                    outer_type,
+                                                    stmt,
                                                     fndecl);
-                 return base;
+                 if (instance)
+                   *instance = base;
+                 return;
                }
              else
                break;
@@ -2562,7 +2580,7 @@ get_polymorphic_call_info (tree fndecl,
       else if (TREE_CODE (base_pointer) == POINTER_PLUS_EXPR
               && tree_fits_uhwi_p (TREE_OPERAND (base_pointer, 1)))
        {
-         context->offset += tree_to_shwi (TREE_OPERAND (base_pointer, 1))
+         offset += tree_to_shwi (TREE_OPERAND (base_pointer, 1))
                    * BITS_PER_UNIT;
          base_pointer = TREE_OPERAND (base_pointer, 0);
        }
@@ -2580,19 +2598,22 @@ get_polymorphic_call_info (tree fndecl,
       if (TREE_CODE (TREE_TYPE (fndecl)) == METHOD_TYPE
          && SSA_NAME_VAR (base_pointer) == DECL_ARGUMENTS (fndecl))
        {
-         context->outer_type
+         outer_type
             = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (base_pointer)));
-         gcc_assert (TREE_CODE (context->outer_type) == RECORD_TYPE);
+         gcc_assert (TREE_CODE (outer_type) == RECORD_TYPE);
 
          /* Dynamic casting has possibly upcasted the type
             in the hiearchy.  In this case outer type is less
             informative than inner type and we should forget
             about it.  */
-         if (!contains_type_p (context->outer_type, context->offset,
-                               *otr_type))
+         if (otr_type
+             && !contains_type_p (outer_type, offset,
+                                  otr_type))
            {
-             context->outer_type = NULL;
-             return base_pointer;
+             outer_type = NULL;
+             if (instance)
+               *instance = base_pointer;
+             return;
            }
 
          /* If the function is constructor or destructor, then
@@ -2601,38 +2622,41 @@ get_polymorphic_call_info (tree fndecl,
          if (DECL_CXX_CONSTRUCTOR_P (fndecl)
              || DECL_CXX_DESTRUCTOR_P (fndecl))
            {
-             context->maybe_in_construction = true;
-             context->maybe_derived_type = false;
+             maybe_in_construction = true;
+             maybe_derived_type = false;
            }
          else
            {
-             context->maybe_derived_type = true;
-             context->maybe_in_construction = false;
+             maybe_derived_type = true;
+             maybe_in_construction = false;
            }
-         return base_pointer;
+         if (instance)
+           *instance = base_pointer;
+         return;
        }
       /* Non-PODs passed by value are really passed by invisible
         reference.  In this case we also know the type of the
         object.  */
       if (DECL_BY_REFERENCE (SSA_NAME_VAR (base_pointer)))
        {
-         context->outer_type
+         outer_type
             = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (base_pointer)));
-         gcc_assert (!POINTER_TYPE_P (context->outer_type));
+         gcc_assert (!POINTER_TYPE_P (outer_type));
          /* Only type inconsistent programs can have otr_type that is
             not part of outer type.  */
-         if (!contains_type_p (context->outer_type, context->offset,
-                               *otr_type))
+         if (!contains_type_p (outer_type, offset,
+                               otr_type))
            { 
-             /* Use OTR_TOKEN = INT_MAX as a marker of probably type inconsistent
-                code sequences; we arrange the calls to be builtin_unreachable
-                later.  */
-             *otr_token = INT_MAX;
-             return base_pointer;
+             invalid = true;
+             if (instance)
+               *instance = base_pointer;
+             return;
            }
-         context->maybe_derived_type = false;
-         context->maybe_in_construction = false;
-          return base_pointer;
+         maybe_derived_type = false;
+         maybe_in_construction = false;
+         if (instance)
+           *instance = base_pointer;
+         return;
        }
     }
 
@@ -2642,11 +2666,10 @@ get_polymorphic_call_info (tree fndecl,
       && SSA_NAME_IS_DEFAULT_DEF (base_pointer)
       && TREE_CODE (SSA_NAME_VAR (base_pointer)) != PARM_DECL)
     {
-      /* Use OTR_TOKEN = INT_MAX as a marker of probably type inconsistent
-        code sequences; we arrange the calls to be builtin_unreachable
-        later.  */
-      *otr_token = INT_MAX;
-      return base_pointer;
+      invalid = true;
+      if (instance)
+       *instance = base_pointer;
+      return;
     }
   if (TREE_CODE (base_pointer) == SSA_NAME
       && SSA_NAME_DEF_STMT (base_pointer)
@@ -2655,19 +2678,22 @@ get_polymorphic_call_info (tree fndecl,
                            (SSA_NAME_DEF_STMT (base_pointer)));
  
   if (POINTER_TYPE_P (base_type)
-      && contains_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (base_type)),
-                         context->offset,
-                         *otr_type))
+      && (otr_type
+         || !contains_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (base_type)),
+                              offset,
+                              otr_type)))
     {
-      context->speculative_outer_type = TYPE_MAIN_VARIANT
+      speculative_outer_type = TYPE_MAIN_VARIANT
                                          (TREE_TYPE (base_type));
-      context->speculative_offset = context->offset;
-      context->speculative_maybe_derived_type = true;
+      speculative_offset = offset;
+      speculative_maybe_derived_type = true;
     }
   /* TODO: There are multiple ways to derive a type.  For instance
      if BASE_POINTER is passed to an constructor call prior our refernece.
      We do not make this type of flow sensitive analysis yet.  */
-  return base_pointer;
+  if (instance)
+    *instance = base_pointer;
+  return;
 }
 
 /* Structure to be passed in between detect_type_change and
@@ -3404,9 +3430,6 @@ struct final_warning_record *final_warning_records;
    temporarily change to one of base types.  INCLUDE_DERIVER_TYPES make
    us to walk the inheritance graph for all derivations.
 
-   OTR_TOKEN == INT_MAX is used to mark calls that are provably
-   undefined and should be redirected to unreachable.
-
    If COMPLETEP is non-NULL, store true if the list is complete. 
    CACHE_TOKEN (if non-NULL) will get stored to an unique ID of entry
    in the target cache.  If user needs to visit every target list
@@ -3443,23 +3466,12 @@ possible_polymorphic_call_targets (tree otr_type,
 
   otr_type = TYPE_MAIN_VARIANT (otr_type);
 
-  /* If ODR is not initialized, return empty incomplete list.  */
-  if (!odr_hash)
+  /* If ODR is not initialized or the constext is invalid, return empty
+     incomplete list.  */
+  if (!odr_hash || context.invalid)
     {
       if (completep)
-       *completep = false;
-      if (cache_token)
-       *cache_token = NULL;
-      if (speculative_targetsp)
-       *speculative_targetsp = 0;
-      return nodes;
-    }
-
-  /* If we hit type inconsistency, just return empty list of targets.  */
-  if (otr_token == INT_MAX)
-    {
-      if (completep)
-       *completep = true;
+       *completep = context.invalid;
       if (cache_token)
        *cache_token = NULL;
       if (speculative_targetsp)
@@ -3853,6 +3865,26 @@ possible_polymorphic_call_target_p (tree otr_type,
 }
 
 
+
+/* Return true if N can be possibly target of a polymorphic call of
+   OBJ_TYPE_REF expression REF in STMT.  */
+
+bool
+possible_polymorphic_call_target_p (tree ref,
+                                   gimple stmt,
+                                   struct cgraph_node *n)
+{
+  ipa_polymorphic_call_context context (current_function_decl, ref, stmt);
+  tree call_fn = gimple_call_fn (stmt);
+
+  return possible_polymorphic_call_target_p (obj_type_ref_class (call_fn),
+                                            tree_to_uhwi
+                                              (OBJ_TYPE_REF_TOKEN (call_fn)),
+                                            context,
+                                            n);
+}
+
+
 /* After callgraph construction new external nodes may appear.
    Add them into the graph.  */
 
index bbb417dead5629949eeae77fbd55f131e7363254..9223f3a2f5802c77f41e1d5b67a2ffd47c42511e 100644 (file)
@@ -2347,14 +2347,13 @@ ipa_analyze_call_uses (struct func_body_info *fbi, gimple call)
     {
       tree otr_type;
       HOST_WIDE_INT otr_token;
-      ipa_polymorphic_call_context context;
       tree instance;
       tree target = gimple_call_fn (call);
+      ipa_polymorphic_call_context context (current_function_decl,
+                                           target, call, &instance);
 
-      instance = get_polymorphic_call_info (current_function_decl,
-                                           target,
-                                           &otr_type, &otr_token,
-                                           &context, call);
+      otr_type = obj_type_ref_class (target);
+      otr_token = tree_to_uhwi (OBJ_TYPE_REF_TOKEN (target));
 
       if (context.get_dynamic_type (instance,
                                    OBJ_TYPE_REF_OBJECT (target),
@@ -2609,7 +2608,7 @@ ipa_intraprocedural_devirtualization (gimple call)
 #ifdef ENABLE_CHECKING
   if (fndecl)
     gcc_assert (possible_polymorphic_call_target_p
-                 (otr, cgraph_node::get (fndecl)));
+                 (otr, call, cgraph_node::get (fndecl)));
 #endif
   return fndecl;
 }
@@ -3121,14 +3120,12 @@ try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
 
   if (TREE_CODE (binfo) != TREE_BINFO)
     {
-      ipa_polymorphic_call_context context;
+      ipa_polymorphic_call_context context (binfo,
+                                           ie->indirect_info->otr_type,
+                                           ie->indirect_info->offset);
       vec <cgraph_node *>targets;
       bool final;
 
-      if (!get_polymorphic_call_info_from_invariant
-            (&context, binfo, ie->indirect_info->otr_type,
-             ie->indirect_info->offset))
-       return NULL;
       targets = possible_polymorphic_call_targets
                 (ie->indirect_info->otr_type,
                  ie->indirect_info->otr_token,
index 9c81d5c639df6d48eeda9e68860d72b10ed228de..c81232cfccee994e72114365de5931d2ff7d64e2 100644 (file)
@@ -53,12 +53,28 @@ public:
   /* True if speculative outer object may be of derived type.  We always
      speculate that construction does not happen.  */
   bool speculative_maybe_derived_type;
+  /* True if the context is invalid and all calls should be redirected
+     to BUILTIN_UNREACHABLE.  */
+  bool invalid;
 
   /* Build empty "I know nothing" context.  */
   ipa_polymorphic_call_context ();
-
   /* Build polymorphic call context for indirect call E.  */
   ipa_polymorphic_call_context (cgraph_edge *e);
+  /* Build polymorphic call context for IP invariant CST.
+     If specified, OTR_TYPE specify the type of polymorphic call
+     that takes CST+OFFSET as a prameter.  */
+  ipa_polymorphic_call_context (tree cst, tree otr_type = NULL,
+                               HOST_WIDE_INT offset = 0);
+  /* Build context for pointer REF contained in FNDECL at statement STMT.
+     if INSTANCE is non-NULL, return pointer to the object described by
+     the context.  */
+  ipa_polymorphic_call_context (tree fndecl, tree ref, gimple stmt,
+                               tree *instance = NULL);
+
+  /* Look for vtable stores or constructor calls to work out dynamic type
+     of memory location.  */
+  bool get_dynamic_type (tree, tree, tree, gimple);
 
   /* Make context non-speculative.  */
   void clear_speculation ();
@@ -67,9 +83,9 @@ public:
      containing EXPECTED_TYPE as base class.  */
   bool restrict_to_inner_class (tree expected_type);
 
-  /* Look for vtable stores or constructor calls to work out dynamic type
-     of memory location.  */
-  bool get_dynamic_type (tree, tree, tree, gimple);
+private:
+  void set_by_decl (tree, HOST_WIDE_INT);
+  bool set_by_invariant (tree, tree, HOST_WIDE_INT);
 };
 
 /* Build polymorphic call context for indirect call E.  */
@@ -77,6 +93,8 @@ public:
 inline
 ipa_polymorphic_call_context::ipa_polymorphic_call_context (cgraph_edge *e)
 {
+  gcc_checking_assert (e->indirect_info->polymorphic);
+
   offset = e->indirect_info->offset;
   speculative_offset = e->indirect_info->speculative_offset;
   outer_type = e->indirect_info->outer_type;
@@ -84,16 +102,22 @@ ipa_polymorphic_call_context::ipa_polymorphic_call_context (cgraph_edge *e)
   maybe_in_construction = e->indirect_info->maybe_in_construction;
   maybe_derived_type = e->indirect_info->maybe_derived_type;
   speculative_maybe_derived_type = e->indirect_info->speculative_maybe_derived_type;
+  invalid = false;
 }
 
 /* Build empty "I know nothing" context.  */
 
 inline
 ipa_polymorphic_call_context::ipa_polymorphic_call_context ()
- : offset(0), speculative_offset(0), outer_type(NULL),
-   speculative_outer_type(NULL), maybe_in_construction(false),
-   maybe_derived_type(false), speculative_maybe_derived_type(false)
 {
+  offset = 0;
+  speculative_offset = 0;
+  outer_type = NULL;
+  speculative_outer_type = NULL;
+  maybe_in_construction = true;
+  maybe_derived_type = true;
+  speculative_maybe_derived_type = false;
+  invalid = false;
 }
 
 /* Make context non-speculative.  */
@@ -131,22 +155,17 @@ void update_type_inheritance_graph (void);
 vec <cgraph_node *>
 possible_polymorphic_call_targets (tree, HOST_WIDE_INT,
                                   ipa_polymorphic_call_context,
-                                  bool *final = NULL,
+                                  bool *copletep = NULL,
                                   void **cache_token = NULL,
                                   int *nonconstruction_targets = NULL);
 odr_type get_odr_type (tree, bool insert = false);
+bool possible_polymorphic_call_target_p (tree ref, gimple stmt, struct cgraph_node *n);
 void dump_possible_polymorphic_call_targets (FILE *, tree, HOST_WIDE_INT,
                                             const ipa_polymorphic_call_context &);
 bool possible_polymorphic_call_target_p (tree, HOST_WIDE_INT,
                                         const ipa_polymorphic_call_context &,
                                         struct cgraph_node *);
 tree method_class_type (const_tree);
-tree get_polymorphic_call_info (tree, tree, tree *,
-                               HOST_WIDE_INT *,
-                               ipa_polymorphic_call_context *,
-                               gimple call = NULL);
-bool get_polymorphic_call_info_from_invariant (ipa_polymorphic_call_context *,
-                                              tree, tree, HOST_WIDE_INT);
 bool decl_maybe_in_construction_p (tree, tree, gimple, tree);
 tree vtable_pointer_value_to_binfo (const_tree);
 bool vtable_pointer_value_to_vtable (const_tree, tree *, unsigned HOST_WIDE_INT *);
@@ -155,7 +174,7 @@ bool contains_polymorphic_type_p (const_tree);
 void register_odr_type (tree);
 
 /* Return vector containing possible targets of polymorphic call E.
-   If FINALP is non-NULL, store true if the list is complette. 
+   If COMPLETEP is non-NULL, store true if the list is complette. 
    CACHE_TOKEN (if non-NULL) will get stored to an unique ID of entry
    in the target cache.  If user needs to visit every target list
    just once, it can memoize them.
@@ -166,16 +185,16 @@ void register_odr_type (tree);
 
 inline vec <cgraph_node *>
 possible_polymorphic_call_targets (struct cgraph_edge *e,
-                                  bool *final = NULL,
+                                  bool *completep = NULL,
                                   void **cache_token = NULL,
                                   int *nonconstruction_targets = NULL)
 {
-  gcc_checking_assert (e->indirect_info->polymorphic);
   ipa_polymorphic_call_context context(e);
+
   return possible_polymorphic_call_targets (e->indirect_info->otr_type,
                                            e->indirect_info->otr_token,
                                            context,
-                                           final, cache_token,
+                                           completep, cache_token,
                                            nonconstruction_targets);
 }
 
@@ -184,21 +203,16 @@ possible_polymorphic_call_targets (struct cgraph_edge *e,
 inline vec <cgraph_node *>
 possible_polymorphic_call_targets (tree ref,
                                   gimple call,
-                                  bool *final = NULL,
+                                  bool *completep = NULL,
                                   void **cache_token = NULL)
 {
-  tree otr_type;
-  HOST_WIDE_INT otr_token;
-  ipa_polymorphic_call_context context;
+  ipa_polymorphic_call_context context (current_function_decl, ref, call);
 
-  get_polymorphic_call_info (current_function_decl,
-                            ref,
-                            &otr_type, &otr_token, &context, call);
   return possible_polymorphic_call_targets (obj_type_ref_class (ref),
                                            tree_to_uhwi
                                              (OBJ_TYPE_REF_TOKEN (ref)),
                                            context,
-                                           final, cache_token);
+                                           completep, cache_token);
 }
 
 /* Dump possible targets of a polymorphic call E into F.  */
@@ -206,8 +220,8 @@ possible_polymorphic_call_targets (tree ref,
 inline void
 dump_possible_polymorphic_call_targets (FILE *f, struct cgraph_edge *e)
 {
-  gcc_checking_assert (e->indirect_info->polymorphic);
   ipa_polymorphic_call_context context(e);
+
   dump_possible_polymorphic_call_targets (f, e->indirect_info->otr_type,
                                          e->indirect_info->otr_token,
                                          context);
@@ -221,26 +235,12 @@ possible_polymorphic_call_target_p (struct cgraph_edge *e,
                                    struct cgraph_node *n)
 {
   ipa_polymorphic_call_context context(e);
+
   return possible_polymorphic_call_target_p (e->indirect_info->otr_type,
                                             e->indirect_info->otr_token,
                                             context, n);
 }
 
-/* Return true if N can be possibly target of a polymorphic call of
-   OBJ_TYPE_REF expression CALL.  */
-
-inline bool
-possible_polymorphic_call_target_p (tree call,
-                                   struct cgraph_node *n)
-{
-  ipa_polymorphic_call_context context;
-  return possible_polymorphic_call_target_p (obj_type_ref_class (call),
-                                            tree_to_uhwi
-                                              (OBJ_TYPE_REF_TOKEN (call)),
-                                            context,
-                                            n);
-}
-
 /* Return true of T is type with One Definition Rule info attached. 
    It means that either it is anonymous type or it has assembler name
    set.  */
index 5f32b59096928c9e059d351325bc96f4da54e551..235846ff927a6c017a26c8f439082b4866dd1bf2 100644 (file)
@@ -4277,16 +4277,11 @@ eliminate_dom_walker::before_dom_children (basic_block b)
              && flag_devirtualize
              && virtual_method_call_p (fn))
            {
-             tree otr_type;
-             HOST_WIDE_INT otr_token;
-             ipa_polymorphic_call_context context;
+             tree otr_type = obj_type_ref_class (fn);
              tree instance;
+             ipa_polymorphic_call_context context (current_function_decl, fn, stmt, &instance);
              bool final;
 
-             instance = get_polymorphic_call_info (current_function_decl,
-                                                   fn,
-                                                   &otr_type, &otr_token, &context, stmt);
-
              context.get_dynamic_type (instance, OBJ_TYPE_REF_OBJECT (fn), otr_type, stmt);
 
              vec <cgraph_node *>targets