[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