https://gcc.gnu.org/bugzilla/show_bug.cgi?id=35560

--- Comment #16 from Richard Biener <rguenth at gcc dot gnu.org> ---
(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).

Reply via email to