[cfe-dev] [LLVMdev] Clang devirtualization proposal

Philip Reames listmail at philipreames.com
Fri Jul 31 14:56:39 PDT 2015



On 07/31/2015 02:47 PM, Philip Reames wrote:
>
>
> On 07/29/2015 09:32 AM, Reid Kleckner wrote:
>> On Tue, Jul 28, 2015 at 10:58 AM, Philip Reames 
>> <listmail at philipreames.com <mailto:listmail at philipreames.com>> wrote:
>>
>>     Having read through the proposal, I feel like I missing some of
>>     the background to understand the problem you're trying to solve.
>>
>>     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.
>>
>>     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?
>>
>>     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?
>>
>>
>> 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.
>>
>> 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:
>>
>> struct MyClass {
>>   virtual void foo();
>> };
>> struct MyOtherClass : MyClass {
>>   virtual void foo();
>> };
>> int main() {
>>   MyClass c;
>>   c.foo();
>>   // Reuse the storage temporarily.  UB to access the object through ‘c’
>>   c.~MyClass();
>>   auto c2 = new (&c) MyOtherClass();
>>   c2->foo(); //fine, we have new pointer
>>   // c.foo() // UB, the type has changed
>>   // The storage has to contain a ‘MyClass’ when it goes out of scope.
>>   c2->~MyOtherClass();
>>   new (&c) MyClass(); // we have to get back to previous type because 
>> calling destructor using c would be UB
>> }
>>
>> Without @llvm.invariant.group.barrier, LLVM will probably replace %c2 
>> with %c here, since they are trivially the same.
>>
>> 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.
> So, to phrase this differently, the @llvm.invariant.group.barrier is 
> responsible for introducing a new abstract memory location and the 
> optimizer is agreeing to never exploit the fact the new abstract 
> memory location is in fact at the same address?
>
> Where in the execution would this new abstract location be 
> introduced?  Is it immediately before the placement new?  If so, that 
> would seem consistent.
Sorry, ignore the above.  I got to the part below and forgot to update 
this before sending.  I hadn't yet internalized the bit about not being 
able to reason about disjoint abstract locations when I wrote this.
>
>>
>> There is, however, a small problem with this model. If the code 
>> happened to do this:
>>
>>   ...
>>   auto c2 = new (&c) MyOtherClass();
>>   assert(c2 == &c);
>>   ...
>>
>> LLVM might once again replace %c2 with %c, causing bad devirtualization.
> Is this well defined C++?  My reading would be that it is.  If this 
> was realloc, it clearly wouldn't be, but I'm not sure placement new 
> has the same restrictions.
>
> Assuming that it is well defined C, this was exactly the counter 
> example I was missing and the reason that reasoning about abstract 
> locations per object doesn't work.  Thanks.
>
> Given that, I can see why we're stuck with a single abstract location 
> for the storage and need to add and remove the invariantness of a 
> particular location.  I'll go take another read through the proposal 
> with that in mind.
>
> Philip
>
>
>
> _______________________________________________
> LLVM Developers mailing list
> LLVMdev at cs.uiuc.edu         http://llvm.cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20150731/2ab734ed/attachment.html>


More information about the cfe-dev mailing list