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