[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