From: hubicka Date: Tue, 4 Feb 2014 05:40:21 +0000 (+0000) Subject: * ipa-cp.c (ipa_get_indirect_edge_target_1): Do direct X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=54176a576e3ab9dd6294a841d78d36f4e6d5aadc;p=thirdparty%2Fgcc.git * ipa-cp.c (ipa_get_indirect_edge_target_1): Do direct lookup via vtable pointer; check for type consistency and turn inconsitent facts into UNREACHABLE. * ipa-prop.c (try_make_edge_direct_virtual_call): Likewise. * gimple-fold.c (gimple_get_virt_method_for_vtable): Do not ICE on type inconsistent querries; return UNREACHABLE instead. * testsuite/g++.dg/ipa/devirt-25.C: New testcase. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@207448 138bc75d-0d04-0410-961f-82ee72b054a4 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 4baab8e13bda..c4c197a6a231 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +2014-02-03 Jan Hubicka + + PR ipa/59831 + * ipa-cp.c (ipa_get_indirect_edge_target_1): Use ipa-devirt + to figure out targets of polymorphic calls with known decl. + * ipa-prop.c (try_make_edge_direct_virtual_call): Likewise. + * ipa-utils.h (get_polymorphic_call_info_from_invariant): Declare. + * ipa-devirt.c (get_polymorphic_call_info_for_decl): Break out from ... + (get_polymorphic_call_info): ... here. + (get_polymorphic_call_info_from_invariant): New function. + 2014-02-03 Jan Hubicka * ipa-cp.c (ipa_get_indirect_edge_target_1): Do direct diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c index e2101769e126..68afeb0d89e4 100644 --- a/gcc/ipa-cp.c +++ b/gcc/ipa-cp.c @@ -1601,15 +1601,24 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie, if (TREE_CODE (t) != TREE_BINFO) { - tree binfo; - binfo = gimple_extract_devirt_binfo_from_cst - (t, ie->indirect_info->otr_type); - if (!binfo) + ipa_polymorphic_call_context context; + vec targets; + bool final; + + if (!get_polymorphic_call_info_from_invariant + (&context, t, ie->indirect_info->otr_type, + anc_offset)) return NULL_TREE; - binfo = get_binfo_at_offset (binfo, anc_offset, otr_type); - if (!binfo) + targets = possible_polymorphic_call_targets + (ie->indirect_info->otr_type, + ie->indirect_info->otr_token, + context, &final); + if (!final || targets.length () > 1) return NULL_TREE; - target = gimple_get_virt_method_for_binfo (token, binfo); + if (targets.length () == 1) + target = targets[0]->decl; + else + target = builtin_decl_implicit (BUILT_IN_UNREACHABLE); } else { diff --git a/gcc/ipa-devirt.c b/gcc/ipa-devirt.c index fb9c666b12d4..f13787481e25 100644 --- a/gcc/ipa-devirt.c +++ b/gcc/ipa-devirt.c @@ -1071,6 +1071,60 @@ vtable_pointer_value_to_binfo (tree t) offset, vtable); } +/* Proudce polymorphic call context for call method of instance + that is located within BASE (that is assumed to be a decl) at OFFSET. */ + +static void +get_polymorphic_call_info_for_decl (ipa_polymorphic_call_context *context, + tree base, HOST_WIDE_INT offset) +{ + gcc_assert (DECL_P (base)); + + context->outer_type = TREE_TYPE (base); + context->offset = offset; + /* 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; +} + +/* 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. + 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) +{ + HOST_WIDE_INT offset2, size, max_size; + tree base; + + if (TREE_CODE (cst) != ADDR_EXPR) + return NULL_TREE; + + cst = TREE_OPERAND (cst, 0); + base = get_ref_base_and_extent (cst, &offset2, &size, &max_size); + if (!DECL_P (base) + || max_size == -1 + || max_size != size) + return NULL_TREE; + + /* 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 NULL_TREE; + + get_polymorphic_call_info_for_decl (context, + base, offset); + return true; +} + /* Given REF call in FNDECL, determine class of the polymorphic call (OTR_TYPE), its token (OTR_TOKEN) and CONTEXT. Return pointer to object described by the context */ @@ -1136,14 +1190,8 @@ get_polymorphic_call_info (tree fndecl, if (!contains_type_p (TREE_TYPE (base), context->offset + offset2, *otr_type)) return base_pointer; - context->outer_type = TREE_TYPE (base); - context->offset += offset2; - /* 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; + get_polymorphic_call_info_for_decl (context, base, + context->offset + offset2); return NULL; } else diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c index 39c01c51ef3e..69566e9f3a88 100644 --- a/gcc/ipa-prop.c +++ b/gcc/ipa-prop.c @@ -2731,19 +2731,38 @@ try_make_edge_direct_virtual_call (struct cgraph_edge *ie, if (TREE_CODE (binfo) != TREE_BINFO) { - binfo = gimple_extract_devirt_binfo_from_cst - (binfo, ie->indirect_info->otr_type); - if (!binfo) + ipa_polymorphic_call_context context; + vec 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, + context, &final); + if (!final || targets.length () > 1) return NULL; + if (targets.length () == 1) + target = targets[0]->decl; + else + { + target = builtin_decl_implicit (BUILT_IN_UNREACHABLE); + cgraph_get_create_node (target); + } } - - binfo = get_binfo_at_offset (binfo, ie->indirect_info->offset, - ie->indirect_info->otr_type); - if (binfo) - target = gimple_get_virt_method_for_binfo (ie->indirect_info->otr_token, - binfo); else - return NULL; + { + binfo = get_binfo_at_offset (binfo, ie->indirect_info->offset, + ie->indirect_info->otr_type); + if (binfo) + target = gimple_get_virt_method_for_binfo (ie->indirect_info->otr_token, + binfo); + else + return NULL; + } if (target) { diff --git a/gcc/ipa-utils.h b/gcc/ipa-utils.h index 3f9be1795bf6..d595e8a969bb 100644 --- a/gcc/ipa-utils.h +++ b/gcc/ipa-utils.h @@ -87,6 +87,8 @@ tree method_class_type (tree); tree get_polymorphic_call_info (tree, tree, tree *, HOST_WIDE_INT *, ipa_polymorphic_call_context *); +bool get_polymorphic_call_info_from_invariant (ipa_polymorphic_call_context *, + tree, tree, HOST_WIDE_INT); tree vtable_pointer_value_to_binfo (tree t); bool vtable_pointer_value_to_vtable (tree, tree *, unsigned HOST_WIDE_INT *); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 3a0c9447dccb..131b6c9a1256 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2014-02-03 Jan Hubicka + + PR ipa/59831 + * g++.dg/ipa/devirt-22.C: New testcase. + 2014-02-03 Jan Hubicka * g++.dg/ipa/devirt-25.C: New testcase. diff --git a/gcc/testsuite/g++.dg/ipa/devirt-22.C b/gcc/testsuite/g++.dg/ipa/devirt-22.C new file mode 100644 index 000000000000..8b8279ae0f23 --- /dev/null +++ b/gcc/testsuite/g++.dg/ipa/devirt-22.C @@ -0,0 +1,41 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fno-early-inlining -fno-ipa-sra -fdump-ipa-cp" } */ +class A {}; +class B { +public: + A &operator[](int); +}; +class C : B { +public: + virtual int m_fn1() { return 0; } + A &operator[](int p1) { + int a; + a = m_fn1(); + static_cast(__builtin_expect(a, 0) ?: 0); + return B::operator[](p1); + } +}; + +C b; +int *e; +static void sort(C &p1, C &p2) { + for (int i=0;; i++) { + A c, d = p2[0]; + p1[0] = c; + p2[0] = d; + } +} + +void lookupSourceDone() { b[0]; } + +void update_sources() { + if (e) { + C f; + sort(f, b); + } +} +/* Note that we miss one devirtualization because we are not able to track the + vtbl store in destructor. + Previously we devirtualized to C::m_fn1 instead of B::m_fn1. */ +/* { dg-final { scan-tree-dump-times "Discovered a virtual call to a known target" 1 "cp" } } */ +/* { dg-final { cleanup-ipa-dump "cp" } } */