[cfe-dev] Optimizing vcalls from structors and virtual this-adjusting thunks
Timur Iskhodzhanov
timurrrr at google.com
Sat Nov 9 05:21:56 PST 2013
2013/11/9 Chris Lattner <clattner at apple.com>:
> This sounds bad, please file a bugzilla!
Sure, filed http://llvm.org/PR17863
2013/11/9 John McCall <rjmccall at apple.com>:
> On Nov 8, 2013, at 1:12 PM, Reid Kleckner <rnk at google.com> wrote:
>
> On Thu, Nov 7, 2013 at 7:43 AM, Timur Iskhodzhanov <timurrrr at google.com>
> wrote:
>>
>> Hi John,
>>
>> I've noticed Clang doesn't devirtualize all vcalls in ctors/dtors.
>>
>> e.g. for this code:
>> --------------------------
>> struct A { virtual void a(); };
>> struct B { virtual void b(); };
>> struct C : virtual A, virtual B {
>> C();
>> virtual void key_function();
>> virtual void a();
>> virtual void b();
>> };
>>
>> C::C() { a(); b(); }
>> void C::key_function() {}
>> --------------------------
>> the assembly for C::C() at -O3 is
>> --------------------------
>> _ZN1CC1Ev: # complete ctor
>> pushq %rbx
>> movq %rdi, %rbx
>> movq $_ZTV1C+40, (%rbx)
>> movq $_ZTV1C+88, 8(%rbx)
>> callq _ZN1C1aEv # call to C::a is devirtualized
>> movq (%rbx), %rax
>> movq %rbx, %rdi
>> popq %rbx
>> jmpq *16(%rax) # call to C::b is not!
>
>
> This looks like it was just standard LLVM optimizations forwarding the vptr
> store and evaluating the load from the constant global. Because C::a is
> external, we think it could have modified the vptr, so we fail to
> devirtualize b.
>
>>
>> _ZN1CC2Ev: # base ctor
>> pushq %rbx
>> movq %rdi, %rbx
>> movq (%rsi), %rax
>> movq %rax, (%rbx)
>> movq 8(%rsi), %rcx
>> movq -32(%rax), %rax
>> movq %rcx, (%rbx,%rax)
>> movq 16(%rsi), %rax
>> movq (%rbx), %rcx
>> movq -40(%rcx), %rcx
>> movq %rax, (%rbx,%rcx)
>> movq (%rbx), %rax
>> callq *(%rax) # looks like even C::a is not devirtualized
>> movq (%rbx), %rax
>> movq %rbx, %rdi
>> popq %rbx
>> jmpq *16(%rax) # call C::b is not devirtualized
>
>
> I don't fully understand how VTTs are supposed to work here, but it looks
> like we don't have a vptr store to forward, so LLVM can't devirtualize. It
> would have to be a clang IRGen optimization.
>
> Nick sent some patches to try to teach LLVM that the vptr is usually
> constant across most calls, but they failed to handle certain corner cases
> involving placement new that John raised.
Why generate virtual call (in LL) in the first place?
> I’m sure GCC is just statically recognizing that it’s a virtual call on
> ’this’ occurring within the constructor.
>
> John.
More information about the cfe-dev
mailing list