<html><head><meta http-equiv="Content-Type" content="text/html charset=windows-1252"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;">On Nov 8, 2013, at 1:12 PM, Reid Kleckner <<a href="mailto:rnk@google.com">rnk@google.com</a>> wrote:<br><div><blockquote type="cite"><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></div></div></blockquote><div><br></div></div>I’m sure GCC is just statically recognizing that it’s a virtual call on ’this’ occurring within the constructor.<div><br></div><div>John.</div></body></html>