Commit ffdcdc0b by Jan Hubicka Committed by Jan Hubicka

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
parent 69597e2f
2018-12-15 Jan Hubicka <hubicka@ucw.cz>
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 <krebbel@linux.ibm.com> 2018-12-21 Andreas Krebbel <krebbel@linux.ibm.com>
* config/s390/vector.md ("floatv2div2df2", "floatunsv2div2df2") * config/s390/vector.md ("floatv2div2df2", "floatunsv2div2df2")
...@@ -995,9 +995,22 @@ ipa_polymorphic_call_context::ipa_polymorphic_call_context (tree fndecl, ...@@ -995,9 +995,22 @@ ipa_polymorphic_call_context::ipa_polymorphic_call_context (tree fndecl,
{ {
outer_type outer_type
= TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (base_pointer))); = 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 gcc_assert (TREE_CODE (outer_type) == RECORD_TYPE
|| TREE_CODE (outer_type) == UNION_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 /* Dynamic casting has possibly upcasted the type
in the hiearchy. In this case outer type is less in the hiearchy. In this case outer type is less
informative than inner type and we should forget informative than inner type and we should forget
...@@ -1005,7 +1018,11 @@ ipa_polymorphic_call_context::ipa_polymorphic_call_context (tree fndecl, ...@@ -1005,7 +1018,11 @@ ipa_polymorphic_call_context::ipa_polymorphic_call_context (tree fndecl,
if ((otr_type if ((otr_type
&& !contains_type_p (outer_type, offset, && !contains_type_p (outer_type, offset,
otr_type)) 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; outer_type = NULL;
if (instance) if (instance)
...@@ -1030,7 +1047,15 @@ ipa_polymorphic_call_context::ipa_polymorphic_call_context (tree fndecl, ...@@ -1030,7 +1047,15 @@ ipa_polymorphic_call_context::ipa_polymorphic_call_context (tree fndecl,
maybe_in_construction = false; maybe_in_construction = false;
} }
if (instance) 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; return;
} }
/* Non-PODs passed by value are really passed by invisible /* Non-PODs passed by value are really passed by invisible
...@@ -1547,6 +1572,9 @@ ipa_polymorphic_call_context::get_dynamic_type (tree instance, ...@@ -1547,6 +1572,9 @@ ipa_polymorphic_call_context::get_dynamic_type (tree instance,
HOST_WIDE_INT instance_offset = offset; HOST_WIDE_INT instance_offset = offset;
tree instance_outer_type = outer_type; tree instance_outer_type = outer_type;
if (!instance)
return false;
if (otr_type) if (otr_type)
otr_type = TYPE_MAIN_VARIANT (otr_type); otr_type = TYPE_MAIN_VARIANT (otr_type);
......
...@@ -547,7 +547,11 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node, ...@@ -547,7 +547,11 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node,
streamer_write_bitpack (&bp); streamer_write_bitpack (&bp);
streamer_write_data_stream (ob->main_stream, section, strlen (section) + 1); 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 streamer_write_uhwi_stream
(ob->main_stream, (ob->main_stream,
...@@ -1295,7 +1299,7 @@ input_node (struct lto_file_decl_data *file_data, ...@@ -1295,7 +1299,7 @@ input_node (struct lto_file_decl_data *file_data,
if (section) if (section)
node->set_section_for_node (section); node->set_section_for_node (section);
if (node->thunk.thunk_p) if (node->definition)
{ {
int type = streamer_read_uhwi (ib); int type = streamer_read_uhwi (ib);
HOST_WIDE_INT fixed_offset = streamer_read_uhwi (ib); HOST_WIDE_INT fixed_offset = streamer_read_uhwi (ib);
......
2018-12-15 Jan Hubicka <hubicka@ucw.cz>
PR ipa/88561
* g++.dg/tree-prof/devirt.C: New testcase.
2018-12-21 Paul Thomas <pault@gcc.gnu.org> 2018-12-21 Paul Thomas <pault@gcc.gnu.org>
PR fortran/87881 PR fortran/87881
......
/* { 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 <mozIPersonalDictionary *>(this);
else
foundInterface = static_cast <nsISupportsWeakReference *>(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 <nsISupportsWeakReference *>(&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" } } */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment