> On Dec 6, 2016, at 11:35 AM, Joe Groff <jgr...@apple.com> wrote:
>> On Dec 6, 2016, at 11:29 AM, John McCall <rjmcc...@apple.com 
>> <mailto:rjmcc...@apple.com>> wrote:
>> 
>>> On Dec 6, 2016, at 10:17 AM, Joe Groff via swift-dev <swift-dev@swift.org 
>>> <mailto:swift-dev@swift.org>> wrote:
>>>> On Dec 5, 2016, at 4:24 PM, Michael Gottesman via swift-dev 
>>>> <swift-dev@swift.org <mailto:swift-dev@swift.org>> wrote:
>>>> 
>>>> Hello everyone!
>>>> 
>>>> This is a proposal for 2 instructions needed to express borrowing via SSA 
>>>> at the SIL level. The need for these were discovered while I was 
>>>> prototyping a SIL ownership verifier.
>>>> 
>>>> A html version of the proposal:
>>>> 
>>>> https://gottesmm.github.io/proposals/sil-ownership-value-ssa-operations.html
>>>>  
>>>> <https://gottesmm.github.io/proposals/sil-ownership-value-ssa-operations.html>
>>>> 
>>>> And inline:
>>>> 
>>>> ----
>>>> 
>>>> # Summary
>>>> 
>>>> This document proposes the addition of the following new SIL instructions:
>>>> 
>>>> 1. `store_borrow`
>>>> 2. `begin_borrow`
>>>> 
>>>> These enable the expression of the following operations in Semantic SIL:
>>>> 
>>>> 1. Passing an `@guaranteed` value to an `@in_guaranteed` argument without
>>>> performing a copy. (`store_borrow`)
>>>> 2. Copying a field from an `@owned` aggregate without consuming or copying 
>>>> the entire
>>>> aggregate. (`begin_borrow`)
>>>> 3. Passing an `@owned` value as an `@guaranteed` argument parameter.
>>>> 
>>>> # Definitions
>>>> 
>>>> ## store_borrow
>>>> 
>>>> Define `store_borrow` as:
>>>> 
>>>>  store_borrow %x to %y : $*T
>>>>  ...
>>>>  end_borrow %y from %x : $*T, $T
>>>> 
>>>>    =>
>>>> 
>>>>  store %x to %y
>>>> 
>>>> `store_borrow` is needed to convert `@guaranteed` values to 
>>>> `@in_guaranteed`
>>>> arguments. Without a `store_borrow`, this can only be expressed via an
>>>> inefficient `copy_value` + `store` + `load` + `destroy_value` sequence:
>>>> 
>>>>  sil @g : $@convention(thin) (@in_guaranteed Foo) -> ()
>>>> 
>>>>  sil @f : $@convention(thin) (@guaranteed Foo) -> () {
>>>>  bb0(%0 : $Foo):
>>>>    %1 = function_ref @g : $@convention(thin) (@in_guaranteed Foo) -> ()
>>>>    %2 = alloc_stack $Foo
>>>>    %3 = copy_value %0 : $Foo
>>>>    store %3 to [init] %2 : $Foo
>>>>    apply %1(%2) : $@convention(thin) (@in_guaranteed Foo) -> ()
>>>>    %4 = load [take] %2 : $*Foo
>>>>    destroy_value %4 : $Foo
>>>>    dealloc_stack %2 : $Foo
>>>>    ...
>>>>  }
>>>> 
>>>> `store_borrow` allows us to express this in a more efficient and 
>>>> expressive SIL:
>>>> 
>>>>  sil @f : $@convention(thin) (@guaranteed Foo) -> () {
>>>>  bb0(%0 : $Foo):
>>>>    %1 = function_ref @g : $@convention(thin) (@in_guaranteed Foo) -> ()
>>>>    %2 = alloc_stack $Foo
>>>>    store_borrow %0 to %2 : $*T
>>>>    apply %1(%2) : $@convention(thin) (@in_guaranteed Foo) -> ()
>>>>    end_borrow %2 from %0 : $*T, $T
>>>>    dealloc_stack %2 : $Foo
>>>>    ...
>>>>  }
>>>> 
>>>> **NOTE** Once `@in_guaranteed` arguments become passed as values, 
>>>> `store_borrow`
>>>> will no longer be necessary.
>>>> 
>>>> ## begin_borrow
>>>> 
>>>> Define a `begin_borrow` instruction as:
>>>> 
>>>>  %borrowed_x = begin_borrow %x : $T
>>>>  %borrow_x_field = struct_extract %borrowed_x : $T, #T.field
>>>>  apply %f(%borrowed_x) : $@convention(thin) (@guaranteed T) -> ()
>>>>  end_borrow %borrowed_x from %x : $T, $T
>>>> 
>>>>    =>
>>>> 
>>>>  %x_field = struct_extract %x : $T, #T.field
>>>>  apply %f(%x_field) : $@convention(thin) (@guaranteed T) -> ()
>>>> 
>>>> A `begin_borrow` instruction explicitly converts an `@owned` value to a
>>>> `@guaranteed` value. The result of the `begin_borrow` is paired with an
>>>> `end_borrow` instruction that explicitly represents the end scope of the
>>>> `begin_borrow`.
>>>> 
>>>> `begin_borrow` also allows for the explicit borrowing of an `@owned` value 
>>>> for
>>>> the purpose of passing the value off to an `@guaranteed` parameter.
>>>> 
>>>> *NOTE* Alternatively, we could make it so that *_extract operations started
>>>> borrow scopes, but this would make SIL less explicit from an ownership
>>>> perspective since one wouldn't be able to visually identify the first
>>>> `struct_extract` in a chain of `struct_extract`. In the case of 
>>>> `begin_borrow`,
>>>> there is no question and it is completely explicit.
>>> 
>>> begin_borrow SGTM. Does end_borrow need to be explicit, or could we leave 
>>> it implicit and rely on dataflow diagnostics to ensure the borrowed value's 
>>> lifetime is dominated by the owner's? It seems to me like, even if 
>>> end_borrow is explicit, we'd want a lifetime-shortening pass to shrinkwrap 
>>> end_borrows to the precise lifetime of the borrowed value's uses.
>> 
>> I definitely think it should be explicit, as Michael has it.
> 
> Would you be able to elaborate why? I suppose explicit is a more conservative 
> starting point. It feels to me like making it explicit isn't doing much more 
> than imposing more verification and optimization burden on us, but I'm 
> probably missing something.

Well, for one, that verification burden isn't unimportant.  Under ownership, DI 
has to enforce things about borrowed values during the lifetime of the borrow.  
I expect that to apply to values and not just variables.  Having lifetimes 
marked out explicitly should make that much saner.

It's also quite a bit easier to verify things when there's a simple nesting 
property, e.g.
  %1 = load_borrow %0
  %2 = struct_element borrow %1, $foo
  %3 = blah
  end_borrow %2
  end_borrow %1
as opposed to tracking that uses of %2 implicitly require both %2 and %1 to 
have remained borrowed.

For another, it's not obvious that borrowing is a trivial operation.  If 
borrowing can change representations, as it does in Rust and as we might have 
to do in Swift (for tuples at least, maybe for arrays/strings/whatever), then 
something needs to represent the lifetime of that representation, and creating 
it for an opaque T may be non-trivial.

And even if we don't need to generate code normally at begin_borrow / 
end_borrow points, I can pretty easily imagine that being interesting for 
extra, sanitizer-style instrumentation.

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

Reply via email to