From 390675c87ddc147b6d1982824b329e119ae5148b Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Mon, 3 Feb 2014 00:24:52 +0000 Subject: [PATCH] ipa-devirt.c (subbinfo_with_vtable_at_offset, [...]): New functions. * ipa-devirt.c (subbinfo_with_vtable_at_offset, vtable_pointer_value_to_binfo): New functions. * ipa-utils.h (vtable_pointer_value_to_binfo): Declare. * ipa-prop.c (extr_type_from_vtbl_ptr_store): Use it. * g++.dg/ipa/devirt-23.C: New testcase. * g++.dg/ipa/devirt-20.C: Fix template. From-SVN: r207413 --- gcc/ChangeLog | 7 +++ gcc/ipa-devirt.c | 64 ++++++++++++++++++++++++++++ gcc/ipa-prop.c | 21 +++++---- gcc/ipa-utils.h | 1 + gcc/testsuite/ChangeLog | 5 +++ gcc/testsuite/g++.dg/ipa/devirt-20.C | 2 +- gcc/testsuite/g++.dg/ipa/devirt-23.C | 49 +++++++++++++++++++++ 7 files changed, 139 insertions(+), 10 deletions(-) create mode 100644 gcc/testsuite/g++.dg/ipa/devirt-23.C diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b08ccc98087f..39e69d378d0d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2014-02-02 Jan Hubicka + + * ipa-devirt.c (subbinfo_with_vtable_at_offset, + vtable_pointer_value_to_binfo): New functions. + * ipa-utils.h (vtable_pointer_value_to_binfo): Declare. + * ipa-prop.c (extr_type_from_vtbl_ptr_store): Use it. + 2014-02-02 Sandra Loosemore * config/nios2/nios2.md (load_got_register): Initialize GOT diff --git a/gcc/ipa-devirt.c b/gcc/ipa-devirt.c index fb03dd2618d1..dcaebdf86593 100644 --- a/gcc/ipa-devirt.c +++ b/gcc/ipa-devirt.c @@ -972,6 +972,70 @@ contains_type_p (tree outer_type, HOST_WIDE_INT offset, return get_class_context (&context, otr_type); } +/* Lookup base of BINFO that has virtual table VTABLE with OFFSET. */ + +static tree +subbinfo_with_vtable_at_offset (tree binfo, tree offset, tree vtable) +{ + tree v = BINFO_VTABLE (binfo); + int i; + tree base_binfo; + + gcc_assert (!v || TREE_CODE (v) == POINTER_PLUS_EXPR); + + if (v && tree_int_cst_equal (TREE_OPERAND (v, 1), offset) + && TREE_OPERAND (TREE_OPERAND (v, 0), 0) == vtable) + return binfo; + for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) + if (polymorphic_type_binfo_p (base_binfo)) + { + base_binfo = subbinfo_with_vtable_at_offset (base_binfo, offset, vtable); + if (base_binfo) + return base_binfo; + } + return NULL; +} + +/* T is known constant value of virtual table pointer. Return BINFO of the + instance type. */ + +tree +vtable_pointer_value_to_binfo (tree t) +{ + /* We expect &MEM[(void *)&virtual_table + 16B]. + We obtain object's BINFO from the context of the virtual table. + This one contains pointer to virtual table represented via + POINTER_PLUS_EXPR. Verify that this pointer match to what + we propagated through. + + In the case of virtual inheritance, the virtual tables may + be nested, i.e. the offset may be different from 16 and we may + need to dive into the type representation. */ + if (t && TREE_CODE (t) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (t, 0)) == MEM_REF + && TREE_CODE (TREE_OPERAND (TREE_OPERAND (t, 0), 0)) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (TREE_OPERAND (t, 0), 1)) == INTEGER_CST + && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (TREE_OPERAND (t, 0), 0), 0)) + == VAR_DECL) + && DECL_VIRTUAL_P (TREE_OPERAND (TREE_OPERAND + (TREE_OPERAND (t, 0), 0), 0))) + { + tree vtable = TREE_OPERAND (TREE_OPERAND (TREE_OPERAND (t, 0), 0), 0); + tree offset = TREE_OPERAND (TREE_OPERAND (t, 0), 1); + tree binfo = TYPE_BINFO (DECL_CONTEXT (vtable)); + + binfo = subbinfo_with_vtable_at_offset (binfo, offset, vtable); + + /* FIXME: for stores of construction vtables we return NULL, + because we do not have BINFO for those. Eventually we should fix + our representation to allow this case to be handled, too. + In the case we see store of BINFO we however may assume + that standard folding will be ale to cope with it. */ + return binfo; + } + return NULL; +} + /* 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 */ diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c index f8a1ca4f3d44..3024414ab8ac 100644 --- a/gcc/ipa-prop.c +++ b/gcc/ipa-prop.c @@ -591,7 +591,7 @@ static tree extr_type_from_vtbl_ptr_store (gimple stmt, struct type_change_info *tci) { HOST_WIDE_INT offset, size, max_size; - tree lhs, rhs, base; + tree lhs, rhs, base, binfo; if (!gimple_assign_single_p (stmt)) return NULL_TREE; @@ -599,13 +599,7 @@ extr_type_from_vtbl_ptr_store (gimple stmt, struct type_change_info *tci) lhs = gimple_assign_lhs (stmt); rhs = gimple_assign_rhs1 (stmt); if (TREE_CODE (lhs) != COMPONENT_REF - || !DECL_VIRTUAL_P (TREE_OPERAND (lhs, 1)) - || TREE_CODE (rhs) != ADDR_EXPR) - return NULL_TREE; - rhs = get_base_address (TREE_OPERAND (rhs, 0)); - if (!rhs - || TREE_CODE (rhs) != VAR_DECL - || !DECL_VIRTUAL_P (rhs)) + || !DECL_VIRTUAL_P (TREE_OPERAND (lhs, 1))) return NULL_TREE; base = get_ref_base_and_extent (lhs, &offset, &size, &max_size); @@ -624,7 +618,16 @@ extr_type_from_vtbl_ptr_store (gimple stmt, struct type_change_info *tci) else if (tci->object != base) return NULL_TREE; - return DECL_CONTEXT (rhs); + binfo = vtable_pointer_value_to_binfo (rhs); + + /* FIXME: vtable_pointer_value_to_binfo may return BINFO of a + base of outer type. In this case we would need to either + work on binfos or translate it back to outer type and offset. + KNOWN_TYPE jump functions are not ready for that, yet. */ + if (!binfo || TYPE_BINFO (BINFO_TYPE (binfo)) != binfo) + return NULL; + + return BINFO_TYPE (binfo); } /* Callback of walk_aliased_vdefs and a helper function for diff --git a/gcc/ipa-utils.h b/gcc/ipa-utils.h index 8e32fb22d5fa..3212f38cc4c0 100644 --- a/gcc/ipa-utils.h +++ b/gcc/ipa-utils.h @@ -87,6 +87,7 @@ tree method_class_type (tree); tree get_polymorphic_call_info (tree, tree, tree *, HOST_WIDE_INT *, ipa_polymorphic_call_context *); +tree vtable_pointer_value_to_binfo (tree t); /* Return vector containing possible targets of polymorphic call E. If FINALP is non-NULL, store true if the list is complette. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 0e17c17166a6..284b5bbd52e8 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,6 +1,11 @@ 2014-02-02 Jan Hubicka * g++.dg/ipa/devirt-23.C: New testcase. + * g++.dg/ipa/devirt-20.C: Fix template. + +2014-02-02 Jan Hubicka + + * g++.dg/ipa/devirt-21.C: New testcase. 2014-02-02 Richard Sandiford diff --git a/gcc/testsuite/g++.dg/ipa/devirt-20.C b/gcc/testsuite/g++.dg/ipa/devirt-20.C index aee95147a634..0ea245bafdf4 100644 --- a/gcc/testsuite/g++.dg/ipa/devirt-20.C +++ b/gcc/testsuite/g++.dg/ipa/devirt-20.C @@ -28,4 +28,4 @@ main(void) return 0; } /* { dg-final { scan-tree-dump-not "abort" "release_ssa" } } */ -/* { dg-final { cleanup-ipa-dump "release_ssa" } } */ +/* { dg-final { cleanup-tree-dump "release_ssa" } } */ diff --git a/gcc/testsuite/g++.dg/ipa/devirt-23.C b/gcc/testsuite/g++.dg/ipa/devirt-23.C new file mode 100644 index 000000000000..a32c7d674837 --- /dev/null +++ b/gcc/testsuite/g++.dg/ipa/devirt-23.C @@ -0,0 +1,49 @@ +/* { dg-do run } */ +/* { dg-options "-O3 -fno-partial-inlining -fdump-ipa-cp -fno-devirtualize-speculatively" } */ +/* Main purpose is to verify that we do not produce wrong devirtualization to + C::m_fn1. We currently devirtualize to B::m_fn1, so check that. */ +#include +class A { +public: + unsigned length; +}; +class B {}; +class MultiTermDocs : public virtual B { +protected: + A readerTermDocs; + A subReaders; + virtual B *m_fn1(int *) {} + virtual inline ~MultiTermDocs(); + inline void wrap(void) + { + m_fn1(NULL); + m_fn1(NULL); + m_fn1(NULL); + m_fn1(NULL); + m_fn1(NULL); + m_fn1(NULL); + m_fn1(NULL); + m_fn1(NULL); + m_fn1(NULL); + } +}; +class C : MultiTermDocs { + B *m_fn1(int *); +}; +MultiTermDocs::~MultiTermDocs() { + wrap (); + if (&readerTermDocs) { + B *a; + for (unsigned i = 0; i < subReaders.length; i++) + (a != 0); + } +} + +B *C::m_fn1(int *) { abort (); } + +main() +{ + class C c; +} +/* { dg-final { scan-ipa-dump "Discovered a virtual call to" "cp" } } */ +/* { dg-final { cleanup-ipa-dump "cp" } } */ -- 2.47.2