<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Thu, Nov 7, 2013 at 7:43 AM, Timur Iskhodzhanov <span dir="ltr"><<a href="mailto:timurrrr@google.com" target="_blank">timurrrr@google.com</a>></span> wrote:<br>

<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi John,<br>
<br>
I've noticed Clang doesn't devirtualize all vcalls in ctors/dtors.<br>
<br>
e.g. for this code:<br>
--------------------------<br>
struct A { virtual void a(); };<br>
struct B { virtual void b(); };<br>
struct C : virtual A, virtual B {<br>
  C();<br>
  virtual void key_function();<br>
  virtual void a();<br>
  virtual void b();<br>
};<br>
<br>
C::C() { a(); b(); }<br>
void C::key_function() {}<br>
--------------------------<br>
the assembly for C::C() at -O3 is<br>
--------------------------<br>
_ZN1CC1Ev:  # complete ctor<br>
        pushq   %rbx<br>
        movq    %rdi, %rbx<br>
        movq    $_ZTV1C+40, (%rbx)<br>
        movq    $_ZTV1C+88, 8(%rbx)<br>
        callq   _ZN1C1aEv  # call to C::a is devirtualized<br>
        movq    (%rbx), %rax<br>
        movq    %rbx, %rdi<br>
        popq    %rbx<br>
        jmpq    *16(%rax)  # call to C::b is not!<br></blockquote><div><br></div><div>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.</div>

<div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
_ZN1CC2Ev:  # base ctor<br>
        pushq   %rbx<br>
        movq    %rdi, %rbx<br>
        movq    (%rsi), %rax<br>
        movq    %rax, (%rbx)<br>
        movq    8(%rsi), %rcx<br>
        movq    -32(%rax), %rax<br>
        movq    %rcx, (%rbx,%rax)<br>
        movq    16(%rsi), %rax<br>
        movq    (%rbx), %rcx<br>
        movq    -40(%rcx), %rcx<br>
        movq    %rax, (%rbx,%rcx)<br>
        movq    (%rbx), %rax<br>
        callq   *(%rax)   # looks like even C::a is not devirtualized<br>
        movq    (%rbx), %rax<br>
        movq    %rbx, %rdi<br>
        popq    %rbx<br>
        jmpq    *16(%rax)  # call C::b is not devirtualized<br></blockquote><div><br></div><div>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.</div>

<div><br></div><div>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.</div><div><br>
</div>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
--------------------------<br>
The same pattern holds if I define C::C() as "b(); a();" - only the<br>
first vcall in the complete ctor is devirtualized.<br>
<br>
Does this look like a bug to you?<br>
GCC devirtualizes all four calls in this example...<br>
<br>
I also have a somewhat related ABI question.<br>
Is there any reason to keep virtual this-adjusting thunks in the<br>
vtable when the class is fully constructed?<br>
I think all the offsets between bases are known statically at the end<br>
of the complete object constructor, so a special "final vtable" with<br>
only static this adjusting thunks can be used instead of a regular<br>
vtable?<br>
Am I missing something?<br></blockquote><div><br></div><div><br></div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
--<br>
Thanks,<br>
Timur<br>
_______________________________________________<br>
cfe-dev mailing list<br>
<a href="mailto:cfe-dev@cs.uiuc.edu" target="_blank">cfe-dev@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev</a><br>
</blockquote></div><br></div></div>