From ffdcdc0b5a529a830cbde79e921960b27d69652e Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Fri, 21 Dec 2018 20:13:06 +0100 Subject: [PATCH] re PR ipa/88561 (PGO devirtualization miscompilation of firefox) PR ipa/88561 * ipa-polymorphic-call.c (ipa_polymorphic_call_context::ipa_polymorphic_call_context): Handle arguments of thunks correctly. (ipa_polymorphic_call_context::get_dynamic_context): Be ready for NULL instance pinter. * lto-cgraph.c (lto_output_node): Always stream thunk info. From-SVN: r267338 --- gcc/ChangeLog | 10 ++ gcc/ipa-polymorphic-call.c | 32 +++++- gcc/lto-cgraph.c | 8 +- gcc/testsuite/ChangeLog | 5 + gcc/testsuite/g++.dg/tree-prof/devirt.C | 123 ++++++++++++++++++++++++ 5 files changed, 174 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/g++.dg/tree-prof/devirt.C diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 622e0243994..b8db48863de 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2018-12-15 Jan Hubicka + + PR ipa/88561 + * ipa-polymorphic-call.c + (ipa_polymorphic_call_context::ipa_polymorphic_call_context): Handle + arguments of thunks correctly. + (ipa_polymorphic_call_context::get_dynamic_context): Be ready for + NULL instance pinter. + * lto-cgraph.c (lto_output_node): Always stream thunk info. + 2018-12-21 Andreas Krebbel * config/s390/vector.md ("floatv2div2df2", "floatunsv2div2df2") diff --git a/gcc/ipa-polymorphic-call.c b/gcc/ipa-polymorphic-call.c index 13aca94dd00..6e547335079 100644 --- a/gcc/ipa-polymorphic-call.c +++ b/gcc/ipa-polymorphic-call.c @@ -995,9 +995,22 @@ ipa_polymorphic_call_context::ipa_polymorphic_call_context (tree fndecl, { outer_type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (base_pointer))); + cgraph_node *node = cgraph_node::get (current_function_decl); gcc_assert (TREE_CODE (outer_type) == RECORD_TYPE || TREE_CODE (outer_type) == UNION_TYPE); + /* Handle the case we inlined into a thunk. In this case + thunk has THIS pointer of type bar, but it really receives + address to its base type foo which sits in bar at + 0-thunk.fixed_offset. It starts with code that adds + think.fixed_offset to the pointer to compensate for this. + + Because we walked all the way to the begining of thunk, we now + see pointer &bar-thunk.fixed_offset and need to compensate + for it. */ + if (node->thunk.fixed_offset) + offset -= node->thunk.fixed_offset * BITS_PER_UNIT; + /* Dynamic casting has possibly upcasted the type in the hiearchy. In this case outer type is less informative than inner type and we should forget @@ -1005,7 +1018,11 @@ ipa_polymorphic_call_context::ipa_polymorphic_call_context (tree fndecl, if ((otr_type && !contains_type_p (outer_type, offset, otr_type)) - || !contains_polymorphic_type_p (outer_type)) + || !contains_polymorphic_type_p (outer_type) + /* If we compile thunk with virtual offset, the THIS pointer + is adjusted by unknown value. We can't thus use outer info + at all. */ + || node->thunk.virtual_offset_p) { outer_type = NULL; if (instance) @@ -1030,7 +1047,15 @@ ipa_polymorphic_call_context::ipa_polymorphic_call_context (tree fndecl, maybe_in_construction = false; } if (instance) - *instance = base_pointer; + { + /* If method is expanded thunk, we need to apply thunk offset + to instance pointer. */ + if (node->thunk.virtual_offset_p + || node->thunk.fixed_offset) + *instance = NULL; + else + *instance = base_pointer; + } return; } /* Non-PODs passed by value are really passed by invisible @@ -1547,6 +1572,9 @@ ipa_polymorphic_call_context::get_dynamic_type (tree instance, HOST_WIDE_INT instance_offset = offset; tree instance_outer_type = outer_type; + if (!instance) + return false; + if (otr_type) otr_type = TYPE_MAIN_VARIANT (otr_type); diff --git a/gcc/lto-cgraph.c b/gcc/lto-cgraph.c index 536e73c9ecd..45138fd2f0c 100644 --- a/gcc/lto-cgraph.c +++ b/gcc/lto-cgraph.c @@ -547,7 +547,11 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node, streamer_write_bitpack (&bp); streamer_write_data_stream (ob->main_stream, section, strlen (section) + 1); - if (node->thunk.thunk_p) + /* Stream thunk info always because we use it in + ipa_polymorphic_call_context::ipa_polymorphic_call_context + to properly interpret THIS pointers for thunks that has been converted + to Gimple. */ + if (node->definition) { streamer_write_uhwi_stream (ob->main_stream, @@ -1295,7 +1299,7 @@ input_node (struct lto_file_decl_data *file_data, if (section) node->set_section_for_node (section); - if (node->thunk.thunk_p) + if (node->definition) { int type = streamer_read_uhwi (ib); HOST_WIDE_INT fixed_offset = streamer_read_uhwi (ib); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 687d7006bad..0018d8b3394 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2018-12-15 Jan Hubicka + + PR ipa/88561 + * g++.dg/tree-prof/devirt.C: New testcase. + 2018-12-21 Paul Thomas PR fortran/87881 diff --git a/gcc/testsuite/g++.dg/tree-prof/devirt.C b/gcc/testsuite/g++.dg/tree-prof/devirt.C new file mode 100644 index 00000000000..05c9a26e7a4 --- /dev/null +++ b/gcc/testsuite/g++.dg/tree-prof/devirt.C @@ -0,0 +1,123 @@ +/* { dg-options "-O3 -fdump-tree-dom3" } */ +struct nsISupports +{ + virtual int QueryInterface (const int &aIID, void **aInstancePtr) = 0; + virtual __attribute__((noinline, noclone)) unsigned AddRef (void) = 0; + virtual unsigned Release (void) = 0; +}; + +struct nsIObserver : public nsISupports +{ + virtual int Observe (nsISupports * aSubject, const char *aTopic, const unsigned short *aData) = 0; +}; + +struct nsISupportsWeakReference : public nsISupports +{ + virtual int GetWeakReference (void **_retval) = 0; +}; + +struct nsSupportsWeakReference : public nsISupportsWeakReference +{ + nsSupportsWeakReference () : mProxy (0) {} + virtual int GetWeakReference (void **_retval) override { return 0; } + ~nsSupportsWeakReference () {} + void NoticeProxyDestruction () { mProxy = nullptr; } + void *mProxy; + void ClearWeakReferences (); + bool HasWeakReferences () const { return !!mProxy; } +}; + +struct mozIPersonalDictionary : public nsISupports +{ + virtual int Load (void) = 0; + virtual int Save (void) = 0; + virtual int GetWordList (void **aWordList) = 0; + virtual int Check (const int &word, bool * _retval) = 0; + virtual int AddWord (const int &word) = 0; + virtual int RemoveWord (const int &word) = 0; + virtual int IgnoreWord (const int &word) = 0; + virtual int EndSession (void) = 0; +}; + +struct mozPersonalDictionary final + : public mozIPersonalDictionary, public nsIObserver, public nsSupportsWeakReference +{ + virtual int QueryInterface (const int &aIID, void **aInstancePtr) override; + virtual __attribute__((noinline, noclone)) unsigned AddRef (void) override; + virtual unsigned Release (void) override; + unsigned long mRefCnt; + virtual int Load (void) override { return 0; } + virtual int Save (void) override { return 0; } + virtual int GetWordList (void **aWordList) override { return 0; } + virtual int Check (const int &word, bool * _retval) override { return 0; } + virtual int AddWord (const int &word) override { return 0; } + virtual int RemoveWord (const int &word) override { return 0; } + virtual int IgnoreWord (const int &word) override { return 0; } + virtual int EndSession (void) override { return 0; } + virtual int Observe (nsISupports * aSubject, const char *aTopic, const unsigned short *aData) override { return 0; } + mozPersonalDictionary () : mRefCnt(0) {} + int Init () { return 0; } + virtual ~mozPersonalDictionary () {} + bool mIsLoaded; + bool mSavePending; + void *mFile; + char mMonitor[96]; + char mMonitorSave[96]; + char mDictionaryTable[32]; + char mIgnoreTable[32]; +}; + +unsigned +mozPersonalDictionary::AddRef (void) +{ + unsigned count = ++mRefCnt; + return count; +} + +unsigned +mozPersonalDictionary::Release (void) +{ + unsigned count = --mRefCnt; + if (count == 0) + { + mRefCnt = 1; + delete (this); + return 0; + } + return count; +} + +int +mozPersonalDictionary::QueryInterface (const int &aIID, void **aInstancePtr) +{ + nsISupports *foundInterface; + if (aIID == 122) + foundInterface = static_cast (this); + else + foundInterface = static_cast (this); + int status; + foundInterface->AddRef (); + *aInstancePtr = foundInterface; + return status; +} + +__attribute__((noipa)) int +foo (nsISupports *p, const int &i) +{ + void *q; + return p->QueryInterface (i, &q); +} + +int +main () +{ + mozPersonalDictionary m; + int j = 123; + for (int i = 0; i < 100000; i++) + foo (static_cast (&m), j); + if (m.mRefCnt != 100000) + __builtin_abort (); +} + +/* { dg-final-use-not-autofdo { scan-ipa-dump-times 3 "folding virtual function call to virtual unsigned int mozPersonalDictionary::_ZThn16" "dom3" } } */ +/* { dg-final-use-not-autofdo { scan-ipa-dump-times 3 "folding virtual function call to virtual unsigned int mozPersonalDictionary::AddRef" "dom3" } } */ -- 2.30.2