> On Oct 11, 2016, at 11:44 AM, John McCall <rjmcc...@apple.com> wrote:
> 
>> On Oct 11, 2016, at 11:22 AM, Joe Groff <jgr...@apple.com> wrote:
>>> On Oct 11, 2016, at 11:19 AM, Andrew Trick <atr...@apple.com> wrote:
>>> 
>>> 
>>>> On Oct 11, 2016, at 11:02 AM, Joe Groff <jgr...@apple.com> wrote:
>>>> 
>>>> 
>>>>> On Oct 11, 2016, at 10:50 AM, John McCall <rjmcc...@apple.com> wrote:
>>>>> 
>>>>>> On Oct 11, 2016, at 10:10 AM, Joe Groff via swift-dev 
>>>>>> <swift-dev@swift.org> wrote:
>>>>>>> On Oct 10, 2016, at 6:58 PM, Andrew Trick <atr...@apple.com> wrote:
>>>>>>> 
>>>>>>> 
>>>>>>>> On Oct 10, 2016, at 6:23 PM, Joe Groff <jgr...@apple.com> wrote:
>>>>>>>> 
>>>>>>>> 
>>>>>>>>> On Oct 7, 2016, at 11:10 PM, Andrew Trick via swift-dev 
>>>>>>>>> <swift-dev@swift.org> wrote:
>>>>>>>>> ** World 1: SSA @inout
>>>>>>>>> 
>>>>>>>>> Projecting an element produces a new SILValue. Does this SILValue have
>>>>>>>>> it's own ownership associated with it's lifetime, or is it derived
>>>>>>>>> from it's parent object by looking through projections?
>>>>>>>>> 
>>>>>>>>> Either way, projecting any subelement requires reconstructing the
>>>>>>>>> entire aggregate in SIL, through all nesting levels. This will
>>>>>>>>> generate a massive amount of SILValues. Superficially they all need
>>>>>>>>> their own storage.
>>>>>>>>> 
>>>>>>>>> [We could claim that projections don't need storage, but that only
>>>>>>>>> solves one side of the problem.]
>>>>>>>>> 
>>>>>>>>> [I argue that this actually obscures the producer/consumer
>>>>>>>>> relationship, which is the opposite of the intention of moving to
>>>>>>>>> SSA. Projecting subelements for mutation fundamentally doesn't make
>>>>>>>>> sense. It does make sense to borrow a subelement (not for
>>>>>>>>> mutation). It also makes sense to project a mutable storage
>>>>>>>>> location. The natural way to project a storage location is by
>>>>>>>>> projecting an address...]
>>>>>>>> 
>>>>>>>> I think there's a size threshold at which SSA @inout is manageable, 
>>>>>>>> and might lead to overall better register-oriented code, if the 
>>>>>>>> aggregates can be exploded into a small number of individual values. 
>>>>>>>> The cost of reconstructing the aggregate could be mitigated somewhat 
>>>>>>>> by introducing 'insert' instructions for aggregates to pair with the 
>>>>>>>> projection instructions, similar to how LLVM has 
>>>>>>>> insert/extractelement. "%x = project_value %y.field; %x' = 
>>>>>>>> transform(%x); %y' = insert %y.field, %x" isn't too terrible compared 
>>>>>>>> to the address-oriented formulation. Tracking ownership state through 
>>>>>>>> projections and insertions might tricky; haven't thought about that 
>>>>>>>> aspect.
>>>>>>>> 
>>>>>>>> -Joe
>>>>>>> 
>>>>>>> We would have to make sure SROA+mem2reg could still kick in. If that 
>>>>>>> happens, I don’t think we need to worry about inout ownership semantics 
>>>>>>> anymore. A struct_extract is then essentially a borrow. It’s parent’s 
>>>>>>> lifetime needs to be guaranteed, but I don’t know if the subobject 
>>>>>>> needs explicit scoping in SIL since there’s no inout scopes to worry 
>>>>>>> about and nothing for the runtime to do when the scope ends .
>>>>>>> 
>>>>>>> (Incidentally, this would never happen to a CoW type that has a 
>>>>>>> uniqueness check—to mutate a CoW type, it’s value needs to be in 
>>>>>>> memory). 
>>>>>> 
>>>>>> Does a uniqueness check still need to be associated with a memory 
>>>>>> location once we associate ownership with SSA values? It seems to me 
>>>>>> like it wouldn't necessarily need to be. One thing I'd like us to work 
>>>>>> toward is being able to reliably apply uniqueness checks to rvalues, so 
>>>>>> that code in a "pure functional" style gets the same optimization 
>>>>>> benefits as code that explicitly uses inouts.
>>>>> 
>>>>> As I've pointed out in the past, this doesn't make any semantic sense.  
>>>>> Projecting out a buffer reference as a true r-value creates an 
>>>>> independent value and therefore requires bumping the reference count.  
>>>>> The only query that makes semantic sense is "does this value hold a 
>>>>> unique reference to its buffer", which requires some sort of language 
>>>>> tool for talking abstractly about values without creating new, 
>>>>> independent values.  Our only existing language tool for that is inout, 
>>>>> which allows you to talk about the value stored in a specific mutable 
>>>>> variable.  Ownership will give us a second and more general tool, 
>>>>> borrowing, which allows you abstractly refer to immutable existing values.
>>>> 
>>>> If we have @owned values, then we also have the ability to do a uniqueness 
>>>> check on that value, don't we? This would necessarily consume the value, 
>>>> but we could conditionally produce a new known-unique value on the path 
>>>> where the uniqueness check succeeds.
>>>> 
>>>> entry(%1: @owned $X):
>>>> is_uniquely_referenced %1, yes, no
>>>> yes(%2: /*unique*/ @owned $X):
>>>> // %2 is unique, until copied at least
>>>> no(%3: @owned %X):
>>>> // %3 is not
>>>> 
>>>> -Joe
>>> 
>>> You had to copy $X to make it @owned.
>> 
>> This is the part I think I'm missing. It's not clear to me why this is the 
>> case, though. You could have had an Array return value that has never been 
>> stored in memory, so never needed to be copied. If you have an @inout memory 
>> location, and we enforce the single-owner property on inouts so that they 
>> act like a Rust-style mutable borrow, then you should also be able to take 
>> the value out of the memory location as long as you move a value back in 
>> before the scope of the inout expires.
> 
> I'm not sure what your goal is here vs. relying on borrowing.  Both still 
> require actual analysis to prove uniqueness at any given point, as you note 
> with your "until copied at least" comment.
> 
> Also, from a higher level, I'm not sure why we care whether a value that was 
> semantically an r-value was a unique reference.  CoW types are immutable even 
> if the reference is shared, and that should structurally straightforward to 
> take advantage of under any ownership representation.

My high-level goal was to get to a point where we could support in-place 
optimizations on unique buffers that belong to values that are semantically 
rvalues at the language level. It seems to me that we ought to be able to make 
'stringA + B + C + D' as efficient as '{ var tmp = stringA; tmp += B; tmp += C; 
tmp += D; tmp }()' by enabling uniqueness checks and in-place mutation of the 
unique-by-construction results of +-ing strings. If you think that works under 
the borrow/inout-in-memory model, then no problem; I'm also trying to 
understand the design space a bit more.

-Joe
_______________________________________________
swift-dev mailing list
swift-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-dev

Reply via email to