]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
cgraph.c (cgraph_create_indirect_edge): Update call of get_polymorphic_call_info.
authorJan Hubicka <hubicka@ucw.cz>
Sat, 5 Jul 2014 17:22:44 +0000 (19:22 +0200)
committerJan Hubicka <hubicka@gcc.gnu.org>
Sat, 5 Jul 2014 17:22:44 +0000 (17:22 +0000)
* cgraph.c (cgraph_create_indirect_edge): Update call of
get_polymorphic_call_info.
* ipa-utils.h (get_polymorphic_call_info): Add parameter CALL.
(possible_polymorphic_call_targets): Add parameter call.
(decl_maybe_in_construction_p): New predicate.
(get_polymorphic_call_info): Add parameter call;
use decl_maybe_in_construction_p.
* gimple-fold.c (fold_gimple_assign): Update use of
possible_polymorphic_call_targets.
(gimple_fold_call): Likewise.
* ipa-prop.c: Inlcude calls.h
(ipa_binfo_from_known_type_jfunc): Check that known type is record.
(param_type_may_change_p): New predicate.
(detect_type_change_from_memory_writes): Break out from ...
(detect_type_change): ... this one; use
param_type_may_change_p.
(detect_type_change_ssa): Use param_type_may_change_p.
(compute_known_type_jump_func): Use decl_maybe_in_construction_p.

* g++.dg/ipa/devirt-26.C: Update testcase.
* g++.dg/ipa/imm-devirt-1.C: Update testcase.
* g++.dg/ipa/imm-devirt-2.C: Update testcase.

From-SVN: r212304

gcc/ChangeLog
gcc/cgraph.c
gcc/gimple-fold.c
gcc/ipa-devirt.c
gcc/ipa-prop.c
gcc/ipa-utils.h
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/ipa/devirt-26.C
gcc/testsuite/g++.dg/ipa/imm-devirt-1.C
gcc/testsuite/g++.dg/ipa/imm-devirt-2.C

index d300f6136c0eda46b8827b05958bddaf234f75e2..5cab9dd8ae35c07ac1876300d8adf6e86db28351 100644 (file)
@@ -1,3 +1,24 @@
+2014-07-05  Jan Hubicka   <hubicka@ucw.cz>
+
+       * cgraph.c (cgraph_create_indirect_edge): Update call of
+       get_polymorphic_call_info.
+       * ipa-utils.h (get_polymorphic_call_info): Add parameter CALL.
+       (possible_polymorphic_call_targets): Add parameter call.
+       (decl_maybe_in_construction_p): New predicate.
+       (get_polymorphic_call_info): Add parameter call;
+       use decl_maybe_in_construction_p.
+       * gimple-fold.c (fold_gimple_assign): Update use of
+       possible_polymorphic_call_targets.
+       (gimple_fold_call): Likewise.
+       * ipa-prop.c: Inlcude calls.h
+       (ipa_binfo_from_known_type_jfunc): Check that known type is record.
+       (param_type_may_change_p): New predicate.
+       (detect_type_change_from_memory_writes): Break out from ...
+       (detect_type_change): ... this one; use 
+       param_type_may_change_p.
+       (detect_type_change_ssa): Use param_type_may_change_p.
+       (compute_known_type_jump_func): Use decl_maybe_in_construction_p.
+
 2014-07-05  Charles Baylis  <charles.baylis@linaro.org>
 
        PR target/49423
index 41dcaf9e4a18168f523c205f23f943e3162e814c..4cc8c9bc308f477cbdb40113639bdb1074b4e59c 100644 (file)
@@ -967,7 +967,7 @@ cgraph_create_indirect_edge (struct cgraph_node *caller, gimple call_stmt,
       get_polymorphic_call_info (caller->decl,
                                 target,
                                 &otr_type, &otr_token,
-                                &context);
+                                &context, call_stmt);
 
       /* Only record types can have virtual calls.  */
       gcc_assert (TREE_CODE (otr_type) == RECORD_TYPE);
index 3dcb57602c6edc5b64b9ef4c2f246ca31aff632b..1a9031932abc209e1f6b3f8dd01392dc37f2f396 100644 (file)
@@ -376,7 +376,7 @@ fold_gimple_assign (gimple_stmt_iterator *si)
              {
                bool final;
                vec <cgraph_node *>targets
-                 = possible_polymorphic_call_targets (val, &final);
+                 = possible_polymorphic_call_targets (val, stmt, &final);
                if (final && targets.length () <= 1 && dbg_cnt (devirt))
                  {
                    tree fndecl;
@@ -1125,7 +1125,7 @@ gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace)
        {
          bool final;
          vec <cgraph_node *>targets
-           = possible_polymorphic_call_targets (callee, &final);
+           = possible_polymorphic_call_targets (callee, stmt, &final);
          if (final && targets.length () <= 1 && dbg_cnt (devirt))
            {
              tree lhs = gimple_call_lhs (stmt);
index f7418f175f641da7c6010d0844ab114b714ec6ca..da8dfcfee71271ae6ebb5a62263e0f22cf655098 100644 (file)
@@ -1438,6 +1438,99 @@ vtable_pointer_value_to_binfo (const_tree t)
                                         offset, vtable);
 }
 
+/* We know that the instance is stored in variable or parameter
+   (not dynamically allocated) and we want to disprove the fact
+   that it may be in construction at invocation of CALL.
+
+   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.
+   Check this condition.  This check works safely only before
+   IPA passes, because inline stacks may become out of date
+   later.  */
+
+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));
+
+  /* After inlining the code unification optimizations may invalidate
+     inline stacks.  Also we need to give up on global variables after
+     IPA, because addresses of these may have been propagated to their
+     constructors.  */
+  if (DECL_STRUCT_FUNCTION (function)->after_inlining)
+    return true;
+
+  /* Pure functions can not do any changes on the dynamic type;
+     that require writting to memory.  */
+  if (!auto_var_in_fn_p (base, function)
+      && flags_from_decl_or_type (function) & (ECF_PURE | ECF_CONST))
+    return false;
+
+  for (tree block = gimple_block (call); block && TREE_CODE (block) == BLOCK;
+       block = BLOCK_SUPERCONTEXT (block))
+    if (BLOCK_ABSTRACT_ORIGIN (block)
+       && TREE_CODE (BLOCK_ABSTRACT_ORIGIN (block)) == FUNCTION_DECL)
+      {
+       tree fn = BLOCK_ABSTRACT_ORIGIN (block);
+
+       if (TREE_CODE (TREE_TYPE (fn)) != METHOD_TYPE
+           || (!DECL_CXX_CONSTRUCTOR_P (fn)
+               || !DECL_CXX_DESTRUCTOR_P (fn)))
+         {
+           /* Watch for clones where we constant propagated the first
+              argument (pointer to the instance).  */
+           fn = DECL_ABSTRACT_ORIGIN (fn);
+           if (!fn
+               || !is_global_var (base)
+               || TREE_CODE (TREE_TYPE (fn)) != METHOD_TYPE
+               || (!DECL_CXX_CONSTRUCTOR_P (fn)
+                   || !DECL_CXX_DESTRUCTOR_P (fn)))
+             continue;
+         }
+       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))
+         return true;
+      }
+
+  if (TREE_CODE (base) == VAR_DECL
+      && is_global_var (base))
+    {
+      if (TREE_CODE (TREE_TYPE (function)) != METHOD_TYPE
+         || (!DECL_CXX_CONSTRUCTOR_P (function)
+             || !DECL_CXX_DESTRUCTOR_P (function)))
+       {
+         if (!DECL_ABSTRACT_ORIGIN (function))
+           return false;
+         /* Watch for clones where we constant propagated the first
+            argument (pointer to the instance).  */
+         function = DECL_ABSTRACT_ORIGIN (function);
+         if (!function
+             || TREE_CODE (TREE_TYPE (function)) != METHOD_TYPE
+             || (!DECL_CXX_CONSTRUCTOR_P (function)
+                 || !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))
+       return true;
+    }
+  return false;
+}
+
 /* Proudce polymorphic call context for call method of instance
    that is located within BASE (that is assumed to be a decl) at OFFSET. */
 
@@ -1490,6 +1583,8 @@ get_polymorphic_call_info_from_invariant (ipa_polymorphic_call_context *context,
 
 /* 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  */
 
 tree
@@ -1497,7 +1592,8 @@ get_polymorphic_call_info (tree fndecl,
                           tree ref,
                           tree *otr_type,
                           HOST_WIDE_INT *otr_token,
-                          ipa_polymorphic_call_context *context)
+                          ipa_polymorphic_call_context *context,
+                          gimple call)
 {
   tree base_pointer;
   *otr_type = obj_type_ref_class (ref);
@@ -1561,6 +1657,12 @@ get_polymorphic_call_info (tree fndecl,
                    }
                  get_polymorphic_call_info_for_decl (context, base,
                                                      context->offset + offset2);
+                 if (context->maybe_in_construction && call)
+                   context->maybe_in_construction
+                    = decl_maybe_in_construction_p (base,
+                                                    context->outer_type,
+                                                    call,
+                                                    current_function_decl);
                  return NULL;
                }
              else
index b56921021b820927767ebadf16cd1deb98949c34..34e766d18f1b8a41d38fbbfa2f43d0ddf1cd5719 100644 (file)
@@ -62,6 +62,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "dbgcnt.h"
 #include "domwalk.h"
 #include "builtins.h"
+#include "calls.h"
 
 /* Intermediate information that we get from alias analysis about a particular
    parameter in a particular basic_block.  When a parameter or the memory it
@@ -552,7 +553,11 @@ ipa_set_ancestor_jf (struct ipa_jump_func *jfunc, HOST_WIDE_INT offset,
 tree
 ipa_binfo_from_known_type_jfunc (struct ipa_jump_func *jfunc)
 {
+  if (!RECORD_OR_UNION_TYPE_P (jfunc->value.known_type.base_type))
+    return NULL_TREE;
+
   tree base_binfo = TYPE_BINFO (jfunc->value.known_type.base_type);
+
   if (!base_binfo)
     return NULL_TREE;
   return get_binfo_at_offset (base_binfo,
@@ -731,18 +736,84 @@ check_stmt_for_type_change (ao_ref *ao ATTRIBUTE_UNUSED, tree vdef, void *data)
     return false;
 }
 
+/* See if ARG is PARAM_DECl describing instance passed by pointer
+   or reference in FUNCTION.  Return false if the dynamic type may change
+   in between beggining of the function until CALL is invoked.
 
+   Generally functions are not allowed to change type of such instances,
+   but they call destructors.  We assume that methods can not destroy the THIS
+   pointer.  Also as a special cases, constructor and destructors may change
+   type of the THIS pointer.  */
+
+static bool
+param_type_may_change_p (tree function, tree arg, gimple call)
+{
+  /* Pure functions can not do any changes on the dynamic type;
+     that require writting to memory.  */
+  if (flags_from_decl_or_type (function) & (ECF_PURE | ECF_CONST))
+    return false;
+  /* We need to check if we are within inlined consturctor
+     or destructor (ideally we would have way to check that the
+     inline cdtor is actually working on ARG, but we don't have
+     easy tie on this, so punt on all non-pure cdtors.
+     We may also record the types of cdtors and once we know type
+     of the instance match them.
+
+     Also code unification optimizations may merge calls from
+     different blocks making return values unreliable.  So
+     do nothing during late optimization.  */
+  if (DECL_STRUCT_FUNCTION (function)->after_inlining)
+    return true;
+  if (TREE_CODE (arg) == SSA_NAME
+      && SSA_NAME_IS_DEFAULT_DEF (arg)
+      && TREE_CODE (SSA_NAME_VAR (arg)) == PARM_DECL)
+    {
+      /* Normal (non-THIS) argument.  */
+      if ((SSA_NAME_VAR (arg) != DECL_ARGUMENTS (function)
+          || TREE_CODE (TREE_TYPE (function)) != METHOD_TYPE)
+         /* THIS pointer of an method - here we we want to watch constructors
+            and destructors as those definitely may change the dynamic
+            type.  */
+         || (TREE_CODE (TREE_TYPE (function)) == METHOD_TYPE
+             && !DECL_CXX_CONSTRUCTOR_P (function)
+             && !DECL_CXX_DESTRUCTOR_P (function)
+             && (SSA_NAME_VAR (arg) == DECL_ARGUMENTS (function))))
+       {
+         /* Walk the inline stack and watch out for ctors/dtors.  */
+         for (tree block = gimple_block (call); block && TREE_CODE (block) == BLOCK;
+              block = BLOCK_SUPERCONTEXT (block))
+           if (BLOCK_ABSTRACT_ORIGIN (block)
+               && TREE_CODE (BLOCK_ABSTRACT_ORIGIN (block)) == FUNCTION_DECL)
+             {
+               tree fn = BLOCK_ABSTRACT_ORIGIN (block);
+
+               if (flags_from_decl_or_type (fn) & (ECF_PURE | ECF_CONST))
+                 continue;
+               if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE
+                   && (DECL_CXX_CONSTRUCTOR_P (fn)
+                       || DECL_CXX_DESTRUCTOR_P (fn)))
+                 return true;
+             }
+         return false;
+       }
+    }
+  return true;
+}
 
 /* Detect whether the dynamic type of ARG of COMP_TYPE has changed (before
    callsite CALL) by looking for assignments to its virtual table pointer.  If
    it is, return true and fill in the jump function JFUNC with relevant type
    information or set it to unknown.  ARG is the object itself (not a pointer
    to it, unless dereferenced).  BASE is the base of the memory access as
-   returned by get_ref_base_and_extent, as is the offset.  */
+   returned by get_ref_base_and_extent, as is the offset. 
+
+   This is helper function for detect_type_change and detect_type_change_ssa
+   that does the heavy work which is usually unnecesary.  */
 
 static bool
-detect_type_change (tree arg, tree base, tree comp_type, gimple call,
-                   struct ipa_jump_func *jfunc, HOST_WIDE_INT offset)
+detect_type_change_from_memory_writes (tree arg, tree base, tree comp_type,
+                                      gimple call, struct ipa_jump_func *jfunc,
+                                      HOST_WIDE_INT offset)
 {
   struct type_change_info tci;
   ao_ref ao;
@@ -753,25 +824,6 @@ detect_type_change (tree arg, tree base, tree comp_type, gimple call,
 
   comp_type = TYPE_MAIN_VARIANT (comp_type);
 
-  if (!flag_devirtualize)
-    return false;
-
-  /* C++ methods are not allowed to change THIS pointer unless they
-     are constructors or destructors.  */
-  if (TREE_CODE        (base) == MEM_REF
-      && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME
-      && SSA_NAME_IS_DEFAULT_DEF (TREE_OPERAND (base, 0))
-      && TREE_CODE (SSA_NAME_VAR (TREE_OPERAND (base, 0))) == PARM_DECL
-      && TREE_CODE (TREE_TYPE (current_function_decl)) == METHOD_TYPE
-      && !DECL_CXX_CONSTRUCTOR_P (current_function_decl)
-      && !DECL_CXX_DESTRUCTOR_P (current_function_decl)
-      && (SSA_NAME_VAR (TREE_OPERAND (base, 0))
-         == DECL_ARGUMENTS (current_function_decl)))
-    {
-      gcc_assert (comp_type);
-      return false;
-    }
-
   /* Const calls cannot call virtual methods through VMT and so type changes do
      not matter.  */
   if (!flag_devirtualize || !gimple_vuse (call)
@@ -809,6 +861,28 @@ detect_type_change (tree arg, tree base, tree comp_type, gimple call,
   return true;
 }
 
+/* Detect whether the dynamic type of ARG of COMP_TYPE may have changed.
+   If it is, return true and fill in the jump function JFUNC with relevant type
+   information or set it to unknown.  ARG is the object itself (not a pointer
+   to it, unless dereferenced).  BASE is the base of the memory access as
+   returned by get_ref_base_and_extent, as is the offset.  */
+
+static bool
+detect_type_change (tree arg, tree base, tree comp_type, gimple call,
+                   struct ipa_jump_func *jfunc, HOST_WIDE_INT offset)
+{
+  if (!flag_devirtualize)
+    return false;
+
+  if (TREE_CODE        (base) == MEM_REF
+      && !param_type_may_change_p (current_function_decl,
+                                  TREE_OPERAND (base, 0),
+                                  call))
+    return false;
+  return detect_type_change_from_memory_writes (arg, base, comp_type,
+                                               call, jfunc, offset);
+}
+
 /* Like detect_type_change but ARG is supposed to be a non-dereferenced pointer
    SSA name (its dereference will become the base and the offset is assumed to
    be zero).  */
@@ -822,10 +896,14 @@ detect_type_change_ssa (tree arg, tree comp_type,
       || !POINTER_TYPE_P (TREE_TYPE (arg)))
     return false;
 
+  if (!param_type_may_change_p (current_function_decl, arg, call))
+    return false;
+
   arg = build2 (MEM_REF, ptr_type_node, arg,
                build_int_cst (ptr_type_node, 0));
 
-  return detect_type_change (arg, arg, comp_type, call, jfunc, 0);
+  return detect_type_change_from_memory_writes (arg, arg, comp_type,
+                                               call, jfunc, 0);
 }
 
 /* Callback of walk_aliased_vdefs.  Flags that it has been invoked to the
@@ -1433,11 +1511,15 @@ compute_known_type_jump_func (tree op, struct ipa_jump_func *jfunc,
   if (!DECL_P (base)
       || max_size == -1
       || max_size != size
-      || !contains_polymorphic_type_p (TREE_TYPE (base))
-      || is_global_var (base))
+      || !contains_polymorphic_type_p (TREE_TYPE (base)))
     return;
 
-  if (detect_type_change (op, base, expected_type, call, jfunc, offset))
+  if (decl_maybe_in_construction_p (base, TREE_TYPE (base),
+                                   call, current_function_decl)
+      /* Even if the var seems to be in construction by inline call stack,
+        we may work out the actual type by walking memory writes.  */
+      && (!is_global_var (base)
+         && detect_type_change (op, base, expected_type, call, jfunc, offset)))
     return;
 
   ipa_set_jf_known_type (jfunc, offset, TREE_TYPE (base),
index 82aa23fe4032fa5a42247c7566784a56b080c539..470f4959f3c9b7d4d8b33aba71c5db5a5f9491d4 100644 (file)
@@ -87,9 +87,11 @@ bool possible_polymorphic_call_target_p (tree, HOST_WIDE_INT,
 tree method_class_type (const_tree);
 tree get_polymorphic_call_info (tree, tree, tree *,
                                HOST_WIDE_INT *,
-                               ipa_polymorphic_call_context *);
+                               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 *);
 bool contains_polymorphic_type_p (const_tree);
@@ -125,7 +127,8 @@ possible_polymorphic_call_targets (struct cgraph_edge *e,
 /* Same as above but taking OBJ_TYPE_REF as an parameter.  */
 
 inline vec <cgraph_node *>
-possible_polymorphic_call_targets (tree call,
+possible_polymorphic_call_targets (tree ref,
+                                  gimple call,
                                   bool *final = NULL,
                                   void **cache_token = NULL)
 {
@@ -134,11 +137,11 @@ possible_polymorphic_call_targets (tree call,
   ipa_polymorphic_call_context context;
 
   get_polymorphic_call_info (current_function_decl,
-                            call,
-                            &otr_type, &otr_token, &context);
-  return possible_polymorphic_call_targets (obj_type_ref_class (call),
+                            ref,
+                            &otr_type, &otr_token, &context, call);
+  return possible_polymorphic_call_targets (obj_type_ref_class (ref),
                                            tree_to_uhwi
-                                             (OBJ_TYPE_REF_TOKEN (call)),
+                                             (OBJ_TYPE_REF_TOKEN (ref)),
                                            context,
                                            final, cache_token);
 }
index 93f9d35f71a6ea6f5f13268cfc9195149108dee6..c24f30173ddb29137fe7058f63008a2e0b3afcb8 100644 (file)
@@ -1,3 +1,9 @@
+2014-07-05  Jan Hubicka   <hubicka@ucw.cz>
+
+       * g++.dg/ipa/devirt-26.C: Update testcase.
+       * g++.dg/ipa/imm-devirt-1.C: Update testcase.
+       * g++.dg/ipa/imm-devirt-2.C: Update testcase.
+
 2014-07-04  Tobias Burnus  <burnus@net-b.de>
 
        * gfortran.dg/coarray/coindexed_3.f90: New.
index 469a1402d2509a5c861d2492cbb4ff7bdb550c7c..1787fee86731f2880f0521479d4e7b2428b487b8 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O3 -fdump-ipa-devirt-details"  } */
+/* { dg-options "-O3 -fdump-tree-ccp1"  } */
 struct A
  {
    int a;
@@ -23,7 +23,6 @@ int test(void)
   return d->foo()+b->foo();
 }
 /* The call to b->foo() is perfectly devirtualizable because C can not be in construction
-   when &c was used, but we can not analyze that so far.  Test that we at least speculate
-   that type is in the construction.  */
-/* { dg-final { scan-ipa-dump "speculatively devirtualizing" "devirt"  } } */
-/* { dg-final { cleanup-ipa-dump "devirt" } } */
+   when &c was used.  */
+/* { dg-final { scan-tree-dump-not "OBJ_TYPE_REF" "ccp1"  } } */
+/* { dg-final { cleanup-tree-dump "ccp1" } } */
index 9307d96db099aa12bbf249b5ec7bfe79d4468362..115277ff87093ba6dceb547d6947be2f84839280 100644 (file)
@@ -1,7 +1,7 @@
 /* Verify that virtual calls are folded even early inlining puts them into one
    function with the definition.  */
 /* { dg-do run } */
-/* { dg-options "-O2 -fdump-tree-fre1-details"  } */
+/* { dg-options "-O2 -fdump-tree-einline"  } */
 
 extern "C" void abort (void);
 
@@ -58,5 +58,10 @@ int main (int argc, char *argv[])
   return 0;
 }
 
-/* { dg-final { scan-tree-dump "converting indirect call to function virtual int B::foo" "fre1"  } } */
-/* { dg-final { cleanup-tree-dump "fre1" } } */
+/* middleman_2 gets early inlined and the virtual call should get turned to
+   a direct call.  */
+/* { dg-final { scan-tree-dump "Inlining int middleman_1" "einline"  } } */
+/* { dg-final { scan-tree-dump "Inlining int middleman_2" "einline"  } } */
+/* { dg-final { scan-tree-dump "B::foo (" "einline"  } } */
+/* { dg-final { scan-tree-dump-times "OBJ_TYPE_REF" 2 "einline"  } } */
+/* { dg-final { cleanup-tree-dump "einline" } } */
index 079aa4b6f15c0b37f587fba92d54e1ceaa15f334..58af0898077a474b29ea354d0a2c979b422ff4c8 100644 (file)
@@ -1,7 +1,7 @@
 /* Verify that virtual calls are folded even early inlining puts them into one
    function with the definition.  */
 /* { dg-do run } */
-/* { dg-options "-O2 -fdump-tree-fre1-details"  } */
+/* { dg-options "-O2 -fdump-tree-einline"  } */
 
 extern "C" void abort (void);
 
@@ -91,5 +91,6 @@ int main (int argc, char *argv[])
   return 0;
 }
 
-/* { dg-final { scan-tree-dump "converting indirect call to function" "fre1"  } } */
-/* { dg-final { cleanup-tree-dump "fre1" } } */
+/* We fold into thunk of C. Eventually we should inline the thunk.  */
+/* { dg-final { scan-tree-dump "C::_ZThn24_N1C3fooEi (" "einline"  } } */
+/* { dg-final { cleanup-tree-dump "einline" } } */