From 1986ca43c0202400738d554cbc6c268a7c009a4c Mon Sep 17 00:00:00 2001 From: hubicka Date: Sun, 5 Oct 2014 17:40:28 +0000 Subject: * 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 --- gcc/ChangeLog | 10 ++++++ gcc/ipa-polymorphic-call.c | 59 ++++++++++++++++++++++++++++-------- gcc/ipa-prop.c | 9 +++--- gcc/testsuite/ChangeLog | 9 ++++++ gcc/testsuite/g++.dg/ipa/devirt-42.C | 10 ++---- gcc/testsuite/g++.dg/ipa/devirt-44.C | 1 - gcc/testsuite/g++.dg/ipa/devirt-45.C | 1 - gcc/testsuite/g++.dg/ipa/devirt-46.C | 2 +- gcc/testsuite/g++.dg/ipa/devirt-47.C | 2 +- gcc/testsuite/g++.dg/ipa/devirt-48.C | 32 +++++++++++++++++++ 10 files changed, 108 insertions(+), 27 deletions(-) create mode 100644 gcc/testsuite/g++.dg/ipa/devirt-48.C 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 + + * 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 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 **global_visited = NULL) { + hash_set *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; + if ((*global_visited)->add (op)) + goto done; + } + else + { + if (!visited) + visited = new hash_set; + 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 *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 + + * 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 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(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" } } */ -- cgit v1.2.1