ipa-polymorphic-call.c (possible_placement_new): Fix condition on size.
authorJan Hubicka <hubicka@ucw.cz>
Sun, 5 Oct 2014 17:40:28 +0000 (19:40 +0200)
committerJan Hubicka <hubicka@gcc.gnu.org>
Sun, 5 Oct 2014 17:40:28 +0000 (17:40 +0000)
* ipa-polymorphic-call.c (possible_placement_new): Fix condition
on size.
(ipa_polymorphic_call_context::restrict_to_inner_type): Do not walk
into vptr pointer.
(ipa_polymorphic_call_context::dump): Fix formating.
(walk_ssa_copies): Add logic avoiding loops; update uses.
* ipa-prop.c (ipa_analyze_call_uses): Compute vptr_changed.
* g++.dg/ipa/devirt-42.C: Update template.
* g++.dg/ipa/devirt-44.C: Update template.
* g++.dg/ipa/devirt-45.C: Update template.
* g++.dg/ipa/devirt-46.C: Update template.
* g++.dg/ipa/devirt-47.C: Update template.
* g++.dg/ipa/devirt-48.C: New testcase.

From-SVN: r215902

gcc/ChangeLog
gcc/ipa-polymorphic-call.c
gcc/ipa-prop.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/ipa/devirt-42.C
gcc/testsuite/g++.dg/ipa/devirt-44.C
gcc/testsuite/g++.dg/ipa/devirt-45.C
gcc/testsuite/g++.dg/ipa/devirt-46.C
gcc/testsuite/g++.dg/ipa/devirt-47.C
gcc/testsuite/g++.dg/ipa/devirt-48.C [new file with mode: 0644]

index 25f4495fb3d0bfce0b6ec41d7d4e3550d5e68a8f..59223877fea01579c116ed412affe231a65a8b72 100644 (file)
@@ -1,3 +1,13 @@
+2014-10-04  Jan Hubicka  <hubicka@ucw.cz>
+
+       * ipa-polymorphic-call.c (possible_placement_new): Fix condition
+       on size.
+       (ipa_polymorphic_call_context::restrict_to_inner_type): Do not walk
+       into vptr pointer.
+       (ipa_polymorphic_call_context::dump): Fix formating.
+       (walk_ssa_copies): Add logic avoiding loops; update uses.
+       * ipa-prop.c (ipa_analyze_call_uses): Compute vptr_changed.
+
 2014-10-02  Mark Wielaard  <mjw@redhat.com>
 
        PR debug/63239
index 74226f21a87132a3859b2a6b3ef080f2de4d768c..3e4aa042c3cd8800665b13f3e8db838a90d8ce35 100644 (file)
@@ -97,7 +97,7 @@ possible_placement_new (tree type, tree expected_type,
              || !tree_fits_shwi_p (TYPE_SIZE (type))
              || (cur_offset
                  + (expected_type ? tree_to_uhwi (TYPE_SIZE (expected_type))
-                    : 1)
+                    : GET_MODE_BITSIZE (Pmode))
                  <= tree_to_uhwi (TYPE_SIZE (type)))));
 }
 
@@ -278,6 +278,14 @@ ipa_polymorphic_call_context::restrict_to_inner_class (tree otr_type,
              pos = int_bit_position (fld);
              if (pos > (unsigned HOST_WIDE_INT)cur_offset)
                continue;
+
+             /* Do not consider vptr itself.  Not even for placement new.  */
+             if (!pos && DECL_ARTIFICIAL (fld)
+                 && POINTER_TYPE_P (TREE_TYPE (fld))
+                 && TYPE_BINFO (type)
+                 && polymorphic_type_binfo_p (TYPE_BINFO (type)))
+               continue;
+
              if (!DECL_SIZE (fld) || !tree_fits_uhwi_p (DECL_SIZE (fld)))
                goto no_useful_type_info;
              size = tree_to_uhwi (DECL_SIZE (fld));
@@ -583,7 +591,7 @@ ipa_polymorphic_call_context::dump (FILE *f) const
 {
   fprintf (f, "    ");
   if (invalid)
-    fprintf (f, "Call is known to be undefined\n");
+    fprintf (f, "Call is known to be undefined");
   else
     {
       if (useless_p ())
@@ -751,11 +759,14 @@ ipa_polymorphic_call_context::set_by_invariant (tree cst,
 }
 
 /* See if OP is SSA name initialized as a copy or by single assignment.
-   If so, walk the SSA graph up.  */
+   If so, walk the SSA graph up.  Because simple PHI conditional is considered
+   copy, GLOBAL_VISITED may be used to avoid infinite loop walking the SSA
+   graph.  */
 
 static tree
-walk_ssa_copies (tree op)
+walk_ssa_copies (tree op, hash_set<tree> **global_visited = NULL)
 {
+  hash_set <tree> *visited = NULL;
   STRIP_NOPS (op);
   while (TREE_CODE (op) == SSA_NAME
         && !SSA_NAME_IS_DEFAULT_DEF (op)
@@ -763,6 +774,20 @@ walk_ssa_copies (tree op)
         && (gimple_assign_single_p (SSA_NAME_DEF_STMT (op))
             || gimple_code (SSA_NAME_DEF_STMT (op)) == GIMPLE_PHI))
     {
+      if (global_visited)
+       {
+         if (!*global_visited)
+           *global_visited = new hash_set<tree>;
+         if ((*global_visited)->add (op))
+           goto done;
+       }       
+      else
+       {
+         if (!visited)
+           visited = new hash_set<tree>;
+         if (visited->add (op))
+           goto done;
+       }
       /* Special case
         if (ptr == 0)
           ptr = 0;
@@ -776,23 +801,28 @@ walk_ssa_copies (tree op)
        {
          gimple phi = SSA_NAME_DEF_STMT (op);
 
-         if (gimple_phi_num_args (phi) != 2)
-           return op;
-         if (integer_zerop (gimple_phi_arg_def (phi, 0)))
+         if (gimple_phi_num_args (phi) > 2)
+           goto done;
+         if (gimple_phi_num_args (phi) == 1)
+           op = gimple_phi_arg_def (phi, 0);
+         else if (integer_zerop (gimple_phi_arg_def (phi, 0)))
            op = gimple_phi_arg_def (phi, 1);
          else if (integer_zerop (gimple_phi_arg_def (phi, 1)))
            op = gimple_phi_arg_def (phi, 0);
          else
-           return op;
+           goto done;
        }
       else
        {
          if (gimple_assign_load_p (SSA_NAME_DEF_STMT (op)))
-           return op;
+           goto done;
          op = gimple_assign_rhs1 (SSA_NAME_DEF_STMT (op));
        }
       STRIP_NOPS (op);
     }
+done:
+  if (visited)
+    delete (visited);
   return op;
 }
 
@@ -820,6 +850,7 @@ ipa_polymorphic_call_context::ipa_polymorphic_call_context (tree fndecl,
 {
   tree otr_type = NULL;
   tree base_pointer;
+  hash_set <tree> *visited = NULL;
 
   if (TREE_CODE (ref) == OBJ_TYPE_REF)
     {
@@ -835,9 +866,9 @@ ipa_polymorphic_call_context::ipa_polymorphic_call_context (tree fndecl,
   invalid = false;
 
   /* Walk SSA for outer object.  */
-  do 
+  while (true)
     {
-      base_pointer = walk_ssa_copies (base_pointer);
+      base_pointer = walk_ssa_copies (base_pointer, &visited);
       if (TREE_CODE (base_pointer) == ADDR_EXPR)
        {
          HOST_WIDE_INT size, max_size;
@@ -869,6 +900,8 @@ ipa_polymorphic_call_context::ipa_polymorphic_call_context (tree fndecl,
                 is known.  */
              else if (DECL_P (base))
                {
+                 if (visited)
+                   delete (visited);
                  /* Only type inconsistent programs can have otr_type that is
                     not part of outer type.  */
                  if (otr_type
@@ -907,7 +940,9 @@ ipa_polymorphic_call_context::ipa_polymorphic_call_context (tree fndecl,
       else
        break;
     }
-  while (true);
+
+  if (visited)
+    delete (visited);
 
   /* Try to determine type of the outer object.  */
   if (TREE_CODE (base_pointer) == SSA_NAME
index 80acdcc21bb5ab5010bbc62b41a7f927d3285454..743ea805b6dbb65fab47151ec8b9b693cb971d88 100644 (file)
@@ -2371,9 +2371,10 @@ ipa_analyze_call_uses (struct func_body_info *fbi, gimple call)
       gcc_checking_assert (cs->indirect_info->otr_token
                           == tree_to_shwi (OBJ_TYPE_REF_TOKEN (target)));
 
-      context.get_dynamic_type (instance,
-                               OBJ_TYPE_REF_OBJECT (target),
-                               obj_type_ref_class (target), call);
+      cs->indirect_info->vptr_changed
+       = !context.get_dynamic_type (instance,
+                                    OBJ_TYPE_REF_OBJECT (target),
+                                    obj_type_ref_class (target), call);
       cs->indirect_info->context = context;
     }
 
@@ -3263,7 +3264,7 @@ try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
     {
       if (!possible_polymorphic_call_target_p (ie, cgraph_node::get_create (target)))
        {
-         if (!speculative)
+         if (speculative)
            return NULL;
          target = ipa_impossible_devirt_target (ie, target);
        }
index b3921d61f308936b67787b1eb900685fdd4e5a68..bd7055c53729365f3368fad348e756885d889d4f 100644 (file)
@@ -1,3 +1,12 @@
+2014-10-04  Jan Hubicka  <hubicka@ucw.cz>
+
+       * g++.dg/ipa/devirt-42.C: Update template.
+       * g++.dg/ipa/devirt-44.C: Update template.
+       * g++.dg/ipa/devirt-45.C: Update template.
+       * g++.dg/ipa/devirt-46.C: Update template.
+       * g++.dg/ipa/devirt-47.C: Update template.
+       * g++.dg/ipa/devirt-48.C: New testcase.
+
 2014-10-02  Mark Wielaard  <mjw@redhat.com>
 
        PR debug/63239
index 40076ddf33e6b673ef313530f784c89361616490..e5544eff598166ab85da1da7bc9ced5bf7199666 100644 (file)
@@ -26,13 +26,9 @@ main()
 /* Inlining everything into main makes type clear from type of variable b.
    However devirtualization is also possible for offline copy of A::barbar. Invoking
    B's barbar makes it clear the type is at least B and B is an anonymous
-   namespace type and therefore we know it has no derivations.
-   FIXME: Currently we devirtualize speculatively only because we do not track
-   dynamic type changes well.  */
-/* { dg-final { scan-ipa-dump-times "First type is base of second" 1 "inline"  } } */
-/* { dg-final { scan-ipa-dump-times "Outer types match, merging flags" 2 "inline"  } } */
-/* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a known target" 1 "inline"  } } */
-/* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a speculative target" 1 "inline"  } } */
+   namespace type and therefore we know it has no derivations.  */
+/* { dg-final { scan-ipa-dump-times "First type is base of second" 3 "inline"  } } */
+/* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a known target" 2 "inline"  } } */
 
 /* Verify that speculation is optimized by late optimizers.  */
 /* { dg-final { scan-ipa-dump-times "return 2" 2 "optimized"  } } */
index 4f6ab30cb02c6365d19b6e3f96cfc7b2016ca1a8..bd6c198d8315769882d3c62bbd2bd4110a1a2947 100644 (file)
@@ -27,7 +27,6 @@ main()
    Check that we handle that.  */
 
 /* { dg-final { scan-ipa-dump-times "First type is base of second" 1 "inline"  } } */
-/* { dg-final { scan-ipa-dump "(maybe in construction)" "inline"  } } */
 /* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a known target\[^\\n\]*A::foo" 1 "inline"  } } */
 /* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a known target\[^\\n\]*B::foo" 1 "inline"  } } */
 /* { dg-final { cleanup-ipa-dump "inline" } } */
index 2158c7e59872691731cd4b7e6e7e61704a7e9ea2..5c47e080bf57395977f36648b24592df50111591 100644 (file)
@@ -37,7 +37,6 @@ main()
 }
 
 /* One invocation is A::foo () other is B::foo () even though the type is destroyed and rebuilt in test() */
-/* { dg-final { scan-ipa-dump "(maybe in construction)" "inline"  } } */
 /* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a known target\[^\\n\]*A::foo" 1 "inline"  } } */
 /* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a known target\[^\\n\]*B::foo" 1 "inline"  } } */
 /* { dg-final { cleanup-ipa-dump "inline" } } */
index a6da9c9f62be8a532aa064712025b4ed73e0497d..2648fa9cf3aaf23c622c3619e98454a8ed107a6f 100644 (file)
@@ -20,7 +20,7 @@ m()
   return 0;
 }
 
-/* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a speculative target\[^\\n\]*B::foo" 1 "inline"  } } */
+/* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a known target\[^\\n\]*B::foo" 1 "inline"  } } */
 /* { dg-final { scan-ipa-dump-not "OBJ_TYPE_REF" "optimized"  } } */
 /* { dg-final { scan-ipa-dump-not "abort" "optimized"  } } */
 /* { dg-final { cleanup-ipa-dump "inline" } } */
index 85f7b634342cf17d3fbb05b1a515dae360f25632..364a9ab085eb03aeea7a6a8541a01a8c7b3ad96b 100644 (file)
@@ -23,7 +23,7 @@ m()
   return 0;
 }
 
-/* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a speculative target\[^\\n\]*C::_ZTh" 1 "inline"  } } */
+/* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a known target\[^\\n\]*C::_ZTh" 1 "inline"  } } */
 /* { dg-final { scan-ipa-dump-not "OBJ_TYPE_REF" "optimized"  } } */
 /* FIXME: We ought to inline thunk.  */
 /* { dg-final { scan-ipa-dump "C::_ZThn" "optimized"  } } */
diff --git a/gcc/testsuite/g++.dg/ipa/devirt-48.C b/gcc/testsuite/g++.dg/ipa/devirt-48.C
new file mode 100644 (file)
index 0000000..e1ed274
--- /dev/null
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fno-ipa-cp -fdump-ipa-inline-details -fno-early-inlining" } */
+struct A {
+   virtual int foo(){return 1;}
+};
+struct B:A {
+   virtual int foo(){return 2;}
+   int callfoo(){foo();}
+};
+struct C:A {
+   virtual int foo(){return 3;}
+};
+struct D:B {
+   virtual int foo(){return 4;}
+   int callfoo(){foo();}
+};
+static void
+test (struct A *a)
+{
+  if (a->foo() != 2)
+   __builtin_abort ();
+}
+int
+m()
+{
+  struct A *a = new C;
+  static_cast<B*>(a)->callfoo();
+  return 0;
+}
+
+/* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a known target\[^\\n\]*__builtin_unreachable" 1 "inline"  } } */
+/* { dg-final { cleanup-ipa-dump "inline" } } */