Bug 67184 - Missed optimization with C++11 final specifier
Summary: Missed optimization with C++11 final specifier
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 5.2.0
: P3 enhancement
Target Milestone: 10.0
Assignee: Paolo Carlini
URL:
Keywords:
: 69445 (view as bug list)
Depends on:
Blocks: 95158
  Show dependency treegraph
 
Reported: 2015-08-11 17:51 UTC by Giovanni Deretta
Modified: 2022-05-13 17:40 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2019-04-08 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Giovanni Deretta 2015-08-11 17:51:20 UTC
struct V {
 virtual void foo(); 
};

struct wV final : V {
    
};

struct oV final : V {
  void foo();
  
};

void call(V& x)
{
  x.foo();
}

void call(wV& x)
{
  x.foo();
}

void call(oV& x)
{
  x.foo();
}

# compile with g++ -O3 -std=c++11 

gcc 5.1 and 5.2 on x86-64 generate:

call(V&):
	movq	(%rdi), %rax
	jmp	*(%rax)
call(wV&):
	movq	(%rdi), %rax
	jmp	*(%rax)
call(oV&):
	jmp	oV::foo()

I would expect call(wV&) to generate the same code as call(oV&).

FWIW Clang generates the expected code since about 3.5.
Comment 1 Markus Trippelsdorf 2015-08-11 18:12:17 UTC
Confirmed. Adding CC.
Comment 2 Paolo Carlini 2015-08-12 10:26:34 UTC
Related to c++/65143.
Comment 3 Markus Trippelsdorf 2015-08-12 10:30:14 UTC
(In reply to Paolo Carlini from comment #2)
> Related to c++/65143.

Yes, lets close this one.

*** This bug has been marked as a duplicate of bug 65143 ***
Comment 4 Jonathan Wakely 2016-01-29 10:59:23 UTC
Not a dup, this is a different case.
Comment 5 Jonathan Wakely 2016-01-29 10:59:51 UTC
*** Bug 69445 has been marked as a duplicate of this bug. ***
Comment 6 Jonathan Wakely 2019-04-08 11:24:36 UTC
(In reply to Giovanni Deretta from comment #0)
> I would expect call(wV&) to generate the same code as call(oV&).

Except of course it should be a direct call to V::foo(), not oV::foo().

As I showed in Bug 69445 the devirtualization does happen when the final overrider is in the derived class:

struct Base {
  virtual void foo() const {};
  virtual void bar() const {}
};

struct C final : Base {
  void foo() const { }
};

void func(const C & c) {
  c.foo();  // optimized away
  c.bar();
}

It doesn't happen when the final overrider comes from the base.
Comment 7 Paolo Carlini 2019-05-16 16:28:28 UTC
Seems doable.
Comment 8 paolo@gcc.gnu.org 2019-05-21 22:26:41 UTC
Author: paolo
Date: Tue May 21 22:26:10 2019
New Revision: 271490

URL: https://gcc.gnu.org/viewcvs?rev=271490&root=gcc&view=rev
Log:
/cp
2019-05-21  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/67184
	PR c++/69445
	* call.c (build_over_call): Devirtualize when the final overrider
	comes from the base.

/testsuite
2019-05-21  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/67184
	PR c++/69445
	* g++.dg/other/final3.C: New.
	* g++.dg/other/final4.C: Likewise.
	* g++.dg/other/final5.C: Likewise.

Added:
    trunk/gcc/testsuite/g++.dg/other/final3.C
    trunk/gcc/testsuite/g++.dg/other/final4.C
Modified:
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/call.c
    trunk/gcc/testsuite/ChangeLog
Comment 9 paolo@gcc.gnu.org 2019-05-21 22:27:13 UTC
Author: paolo
Date: Tue May 21 22:26:42 2019
New Revision: 271491

URL: https://gcc.gnu.org/viewcvs?rev=271491&root=gcc&view=rev
Log:
/cp
2019-05-21  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/67184
	PR c++/69445
	* call.c (build_over_call): Devirtualize when the final overrider
	comes from the base.

/testsuite
2019-05-21  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/67184
	PR c++/69445
	* g++.dg/other/final3.C: New.
	* g++.dg/other/final4.C: Likewise.
	* g++.dg/other/final5.C: Likewise.

Added:
    trunk/gcc/testsuite/g++.dg/other/final5.C
Comment 10 Paolo Carlini 2019-05-21 22:28:19 UTC
Fixed.
Comment 11 paolo@gcc.gnu.org 2019-06-21 20:47:23 UTC
Author: paolo
Date: Fri Jun 21 20:46:51 2019
New Revision: 272573

URL: https://gcc.gnu.org/viewcvs?rev=272573&root=gcc&view=rev
Log:
/cp
2019-06-21  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/90909
	Revert:
	2019-05-21  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/67184
	PR c++/69445
	* call.c (build_over_call): Devirtualize when the final overrider
	comes from the base.

/testsuite
2019-06-21  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/90909
	Revert:
	2019-05-21  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/67184
	PR c++/69445
	* g++.dg/other/final3.C: New.
	* g++.dg/other/final4.C: Likewise.
	* g++.dg/other/final5.C: Likewise.

	* g++.dg/other/final6.C: New.

Added:
    trunk/gcc/testsuite/g++.dg/other/final6.C
Modified:
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/call.c
    trunk/gcc/testsuite/ChangeLog
Comment 12 paolo@gcc.gnu.org 2019-06-21 20:48:12 UTC
Author: paolo
Date: Fri Jun 21 20:47:40 2019
New Revision: 272574

URL: https://gcc.gnu.org/viewcvs?rev=272574&root=gcc&view=rev
Log:
/cp
2019-06-21  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/90909
	Revert:
	2019-05-21  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/67184
	PR c++/69445
	* call.c (build_over_call): Devirtualize when the final overrider
	comes from the base.

/testsuite
2019-06-21  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/90909
	Revert:
	2019-05-21  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/67184
	PR c++/69445
	* g++.dg/other/final3.C: New.
	* g++.dg/other/final4.C: Likewise.
	* g++.dg/other/final5.C: Likewise.

	* g++.dg/other/final6.C: New.

Removed:
    trunk/gcc/testsuite/g++.dg/other/final3.C
    trunk/gcc/testsuite/g++.dg/other/final4.C
    trunk/gcc/testsuite/g++.dg/other/final5.C
Comment 13 Paolo Carlini 2019-06-21 20:51:57 UTC
Unfortunately I have to re-open this: the fix, as-is, caused c++/90909.
Comment 14 Paolo Carlini 2019-06-23 21:36:42 UTC
Let's look a bit more into this (with Jason' help)
Comment 15 Paolo Carlini 2019-06-25 16:50:38 UTC
With Jason's r272656 remains to be handled what I had as other/final4.C. final.3.C and final5.C are fine, I'm probably going to add those two to the testsuite.
Comment 16 paolo@gcc.gnu.org 2019-06-26 08:52:21 UTC
Author: paolo
Date: Wed Jun 26 08:51:50 2019
New Revision: 272675

URL: https://gcc.gnu.org/viewcvs?rev=272675&root=gcc&view=rev
Log:
2019-06-26  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/67184
	PR c++/69445
	* g++.dg/other/final3.C: New.
	* g++.dg/other/final5.C: Likewise.

Added:
    trunk/gcc/testsuite/g++.dg/other/final3.C
    trunk/gcc/testsuite/g++.dg/other/final5.C
Modified:
    trunk/gcc/testsuite/ChangeLog
Comment 17 paolo@gcc.gnu.org 2019-07-05 18:03:36 UTC
Author: paolo
Date: Fri Jul  5 18:03:05 2019
New Revision: 273147

URL: https://gcc.gnu.org/viewcvs?rev=273147&root=gcc&view=rev
Log:
/cp
2019-07-05  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/67184 (again)
	PR c++/69445
	* call.c (build_over_call): Devirtualize user-defined operators
	coming from a base too.
	(build_new_method_call_1): Do not devirtualize here.

/testsuite
2019-07-05  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/67184 (again)
	PR c++/69445
	* g++.dg/other/final4.C: New.

Added:
    trunk/gcc/testsuite/g++.dg/other/final4.C
Modified:
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/call.c
    trunk/gcc/testsuite/ChangeLog
Comment 18 Paolo Carlini 2019-07-05 18:05:05 UTC
Finally should be completely fixed without regressions.
Comment 19 Jakub Jelinek 2019-07-05 20:52:15 UTC
Author: jakub
Date: Fri Jul  5 20:51:44 2019
New Revision: 273149

URL: https://gcc.gnu.org/viewcvs?rev=273149&root=gcc&view=rev
Log:
	PR c++/67184
	PR c++/69445
	* call.c (build_new_method_call_1): Remove set but not used variable
	binfo.

Modified:
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/call.c
Comment 20 GCC Commits 2022-05-13 17:40:47 UTC
The releases/gcc-9 branch has been updated by Jason Merrill <jason@gcc.gnu.org>:

https://gcc.gnu.org/g:30a100abe48cebcdf3d685e856850d4192f05ad9

commit r9-10161-g30a100abe48cebcdf3d685e856850d4192f05ad9
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Fri Jul 5 22:51:44 2019 +0200

    re PR c++/67184 (Missed optimization with C++11 final specifier)
    
            PR c++/67184
            PR c++/69445
            * call.c (build_new_method_call_1): Remove set but not used variable
            binfo.