<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Tue, Jul 28, 2015 at 10:58 AM, Philip Reames <span dir="ltr"><<a href="mailto:listmail@philipreames.com" target="_blank">listmail@philipreames.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
  
    
  
  <div bgcolor="#FFFFFF" text="#000000">
    Having read through the proposal, I feel like I missing some of the
    background to understand the problem you're trying to solve.<br>
    <br>
    My mental model is that construction of an object creates a new
    abstract location in an infinite heap with each object infinitely
    far apart.  Destruction of the object destroys the abstract
    location.  As a result, destructing one object and constructing
    another produce unique incomparable abstract locations.  The fact
    the two abstract locations might happen to share a physical address
    is irrelevant.  <br>
    <br>
    If I'm understanding the proposal correctly, this model works for
    most code.  The key optimization you appear to want to perform is to
    recognize the fact that these two abstract locations occupy the same
    memory.  In particular, you want to be able to return mustalias for
    alias(loc1, loc2).  Another way of saying this is that you want to
    reason about abstract locations as defined by
    allocation/deallocation events rather than construction/destruction
    events.  Is that a fair summary?<br>
    <br>
    What I'm not clear on is *why* recognizing the two abstract
    locations share a physical address is important.  Given that the
    contents of the abstract location before construction or after
    destruction are undefined (right?), what optimization does
    recognizing the mustalias relation enable?<br></div></blockquote><div><br></div><div>I think this is incorrect. LLVM's model is closer to the second model, and we need something like the first model to prevent erroneous devirtualization.</div><div><br></div><div>The corner case for C++ is when the optimizer observes that two abstract objects share the same physical memory location. In practice, this could happen if the memory allocator becomes visible to the optimizer through inlining. For illustration, do placement new into the stack memory of another object. This is illustrated in example 2 of the proposal:</div><div><br></div><div><div>struct MyClass {</div><div>  virtual void foo();</div><div>};</div><div>struct MyOtherClass : MyClass {</div><div>  virtual void foo();</div><div>};</div><div>int main() {</div><div>  MyClass c;</div><div>  c.foo();</div><div>  // Reuse the storage temporarily.  UB to access the object through ‘c’</div><div>  c.~MyClass();</div><div>  auto c2 = new (&c) MyOtherClass();</div><div>  c2->foo(); //fine, we have new pointer</div><div>  // c.foo() // UB, the type has changed</div><div>  </div><div>  // The storage has to contain a ‘MyClass’ when it goes out of scope.</div><div>  c2->~MyOtherClass();</div><div>  new (&c) MyClass(); // we have to get back to previous type because calling destructor using c would be UB</div><div>}</div></div><div><br></div><div>Without @llvm.invariant.group.barrier, LLVM will probably replace %c2 with %c here, since they are trivially the same.</div><div><br></div><div>With @llvm.invariant.group.barrier, the result of placement new will be a distinct SSA value that LLVM can't reason about, and we won't accidentally devirtualize c2->foo() to MyClass::foo.</div><div><br></div><div>There is, however, a small problem with this model. If the code happened to do this:</div><div><br></div><div>  ...</div><div><div>  auto c2 = new (&c) MyOtherClass();</div></div><div>  assert(c2 == &c);</div><div>  ...</div><div><br></div><div>LLVM might once again replace %c2 with %c, causing bad devirtualization.</div></div></div></div>