summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>2014-10-05 17:40:28 +0000
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>2014-10-05 17:40:28 +0000
commit1986ca43c0202400738d554cbc6c268a7c009a4c (patch)
tree2798c6a743942ce9aae14e3e6423cb4e162dcdea
parent77cab4753e1206a8a5246f9989b7427990ca0e06 (diff)
downloadgcc-1986ca43c0202400738d554cbc6c268a7c009a4c.tar.gz
* 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@215902 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog10
-rw-r--r--gcc/ipa-polymorphic-call.c59
-rw-r--r--gcc/ipa-prop.c9
-rw-r--r--gcc/testsuite/ChangeLog9
-rw-r--r--gcc/testsuite/g++.dg/ipa/devirt-42.C10
-rw-r--r--gcc/testsuite/g++.dg/ipa/devirt-44.C1
-rw-r--r--gcc/testsuite/g++.dg/ipa/devirt-45.C1
-rw-r--r--gcc/testsuite/g++.dg/ipa/devirt-46.C2
-rw-r--r--gcc/testsuite/g++.dg/ipa/devirt-47.C2
-rw-r--r--gcc/testsuite/g++.dg/ipa/devirt-48.C32
10 files changed, 108 insertions, 27 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 25f4495fb3d..59223877fea 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/ipa-polymorphic-call.c b/gcc/ipa-polymorphic-call.c
index 74226f21a87..3e4aa042c3c 100644
--- a/gcc/ipa-polymorphic-call.c
+++ b/gcc/ipa-polymorphic-call.c
@@ -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
diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
index 80acdcc21bb..743ea805b6d 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -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);
}
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index b3921d61f30..bd7055c5372 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
diff --git a/gcc/testsuite/g++.dg/ipa/devirt-42.C b/gcc/testsuite/g++.dg/ipa/devirt-42.C
index 40076ddf33e..e5544eff598 100644
--- a/gcc/testsuite/g++.dg/ipa/devirt-42.C
+++ b/gcc/testsuite/g++.dg/ipa/devirt-42.C
@@ -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" } } */
diff --git a/gcc/testsuite/g++.dg/ipa/devirt-44.C b/gcc/testsuite/g++.dg/ipa/devirt-44.C
index 4f6ab30cb02..bd6c198d831 100644
--- a/gcc/testsuite/g++.dg/ipa/devirt-44.C
+++ b/gcc/testsuite/g++.dg/ipa/devirt-44.C
@@ -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" } } */
diff --git a/gcc/testsuite/g++.dg/ipa/devirt-45.C b/gcc/testsuite/g++.dg/ipa/devirt-45.C
index 2158c7e5987..5c47e080bf5 100644
--- a/gcc/testsuite/g++.dg/ipa/devirt-45.C
+++ b/gcc/testsuite/g++.dg/ipa/devirt-45.C
@@ -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" } } */
diff --git a/gcc/testsuite/g++.dg/ipa/devirt-46.C b/gcc/testsuite/g++.dg/ipa/devirt-46.C
index a6da9c9f62b..2648fa9cf3a 100644
--- a/gcc/testsuite/g++.dg/ipa/devirt-46.C
+++ b/gcc/testsuite/g++.dg/ipa/devirt-46.C
@@ -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" } } */
diff --git a/gcc/testsuite/g++.dg/ipa/devirt-47.C b/gcc/testsuite/g++.dg/ipa/devirt-47.C
index 85f7b634342..364a9ab085e 100644
--- a/gcc/testsuite/g++.dg/ipa/devirt-47.C
+++ b/gcc/testsuite/g++.dg/ipa/devirt-47.C
@@ -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
index 00000000000..e1ed27477a0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ipa/devirt-48.C
@@ -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" } } */