<html><head></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><br><div><div>On Oct 11, 2010, at 10:43 AM, Kenneth Uildriks wrote:</div><br class="Apple-interchange-newline"><blockquote type="cite"><div>On Mon, Oct 11, 2010 at 12:30 PM, John McCall <<a href="mailto:rjmccall@apple.com">rjmccall@apple.com</a>> wrote:<br><blockquote type="cite">On Oct 11, 2010, at 9:12 AM, Kenneth Uildriks wrote:<br></blockquote><blockquote type="cite"><blockquote type="cite">3. The front-end, recognizing that scribbling on an instance's vtbl<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">pointer has undefined results, eliminated the loads of the vtbl<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">pointer and replaced them with @classvtbl.TestVirtual.  This would<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">allow devirtualization within a function at least, but (I think) would<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">do less to allow analysis to spot devirtualization opportunities<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">across functions.  (Although ArgPromotion could arrange to have the<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">vtbl pointer passed in separately, and then inlining and/or partial<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">specialization could be made to see that it's a pointer to a constant<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">and thus add in the IndirectCallBonus)<br></blockquote></blockquote><blockquote type="cite"><br></blockquote><blockquote type="cite">There are always going to be cases that can only be deduced with<br></blockquote><blockquote type="cite">language knowledge.  We already do some frontend de-virtualization;<br></blockquote><blockquote type="cite">this may just be a missing case.  Can you post your test?<br></blockquote><font class="Apple-style-span" color="#006312"><br></font>I compiled the attached c++ code to bitcode using clang++ -O3, then<br>ran it through opt -std-compile-opts.  I got a reload of the vtbl<br>pointer after the printf call.  The compiler is allowed to cache the<br>vtbl pointer as soon as the object is constructed or passed into a<br>function, right?<br></div></blockquote><div><br></div>Yes.  This is [basic.life]p7, which lists the conditions under which a pointer</div><div>or reference to an object are considered to automatically forward to a new</div><div>object that's created at that location (as opposed to formally still pointing</div><div>at the destroyed object).  One key constraint is that the objects have to be</div><div>of identical type, i.e. their pointers would have to match exactly.  So this is</div><div>a fair optimization as long as we make sure that we keep pointers separate.</div><div><br></div><div>For example, consider the following test case:</div><div><font class="Apple-style-span" face="Courier" size="3"><span class="Apple-style-span" style="font-size: 11px;">  struct A { virtual void foo(); };</span></font></div><div><font class="Apple-style-span" face="Courier" size="3"><span class="Apple-style-span" style="font-size: 11px;">  struct B : A { virtual void foo(); };</span></font></div><div><font class="Apple-style-span" face="Courier" size="3"><span class="Apple-style-span" style="font-size: 11px;">  void test() {</span></font></div><div><font class="Apple-style-span" face="Courier" size="3"><span class="Apple-style-span" style="font-size: 11px;">    A *a = new A();</span></font></div><div><font class="Apple-style-span" face="Courier" size="3"><span class="Apple-style-span" style="font-size: 11px;">    a->foo();  // 1</span></font></div><div><font class="Apple-style-span" face="Courier" size="3"><span class="Apple-style-span" style="font-size: 11px;">    </span></font><span class="Apple-style-span" style="font-family: Courier; font-size: 11px; ">a->foo();  // 2: can assume object type is still A</span></div><div><font class="Apple-style-span" face="Courier" size="3"><span class="Apple-style-span" style="font-size: 11px;">    a->~A();</span></font></div><div><font class="Apple-style-span" face="Courier" size="3"><span class="Apple-style-span" style="font-size: 11px;">    A *b = new (a) B();</span></font></div><div><font class="Apple-style-span" face="Courier" size="3"><span class="Apple-style-span" style="font-size: 11px;">    a->foo();  // 3: illegal use after end of lifetime</span></font></div><div><font class="Apple-style-span" face="Courier" size="3"><span class="Apple-style-span" style="font-size: 11px;">    b->foo();  // 4: okay, can assume object type is still B</span></font></div><div><font class="Apple-style-span" face="Courier" size="3"><span class="Apple-style-span" style="font-size: 11px;">  }</span></font></div><div>Here we happen to be able to prove that 'a' and 'b' have identical values,</div><div>but they nonetheless have different properties for this optimization because</div><div>'a' doesn't meet the criteria for having been forwarded, whereas 'b' points to</div><div>the new object.</div><div><br></div><div>Right now, we don't have any good machinery for doing this kind of</div><div>language-specific optimization in the backend.  Doing it in the front-end</div><div>for your test case would require inter-statement analysis, which we've tried</div><div>to avoid in clang.</div><div><br></div><div>So I think the best bet for this optimization for now is to do it based on the</div><div>knowledge that printf doesn't modify that particular argument.</div><div><br></div><div>John.</div></body></html>