[Bug middle-end/35560] Missing CSE/PRE for memory operations involved in virtual call.
m.cencora at gmail dot com
gcc-bugzilla@gcc.gnu.org
Mon Jan 9 14:30:31 GMT 2023
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=35560
m.cencora at gmail dot com changed:
What |Removed |Added
----------------------------------------------------------------------------
CC| |m.cencora at gmail dot com
--- Comment #17 from m.cencora at gmail dot com ---
It is (In reply to Richard Biener from comment #16)
> (In reply to Witold Baryluk from comment #15)
> > I know this is a pretty old bug, but I was exploring some assembly of gcc
> > and clang on godbolt, and also stumbled into same issue.
> >
> > https://godbolt.org/z/qPzMhWse1
> >
> > class A {
> > public:
> > virtual int f7(int x) const;
> > };
> >
> > int g(const A * const a, int x) {
> > int r = 0;
> > for (int i = 0; i < 10000; i++)
> > r += a->f7(x);
> > return r;
> > }
> >
> > (same happens without loop, when just calling a->f7 multiple times)
> >
> >
> >
> > g(A const*, int):
> > push r13
> > mov r13d, esi
> > push r12
> > xor r12d, r12d
> > push rbp
> > mov rbp, rdi
> > push rbx
> > mov ebx, 10000
> > sub rsp, 8
> > .L2:
> > mov rax, QWORD PTR [rbp+0] # a vtable deref
> > mov esi, r13d
> > mov rdi, rbp
> > call [QWORD PTR [rax]] # f7 indirect call
> > add r12d, eax
> > dec ebx
> > jne .L2
> >
> > add rsp, 8
> > pop rbx
> > pop rbp
> > mov eax, r12d
> > pop r12
> > pop r13
> > ret
> >
> >
> > I was expecting mov rax, QWORD PTR [rbp+0] and call [QWORD PTR
> > [rax]], to be hoisted out of the loop (call converted to lea, and call
> > register).
> >
> >
> > A bit sad.
> >
> > Is there some recent work done on this optimization?
> >
> > Are there at least some cases where it is valid to do CSE, or change code so
> > it is moved out of the loop?
>
> GCC sees a->f() as possibly altering the virtual table [pointer] since
> the function gets passed 'a' and thus a pointer to it (and *a is global
> memory anyway, so GCC has to assume f() has access to it).
>
> In C++ probably there's probably no virtual function that could do this.
> A virtual DTOR would leave an uninitialized object. Not sure if
>
> class A
> {
> virtual void f() { }
> }
> class B : A
> {
> virtual void f() { new A (this); }
> }
>
> would be valid (maybe with first calling the DTOR on the existing object).
It is valid, but to be able to use B object after B::f was invoked (and a new
object is placed there instead), a user need to launder the pointer.
https://en.cppreference.com/w/cpp/utility/launder
More information about the Gcc-bugs
mailing list