> 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