> On Dec 6, 2016, at 11:29 AM, John McCall <rjmcc...@apple.com> wrote:
> 
>> On Dec 6, 2016, at 10:17 AM, Joe Groff via swift-dev <swift-dev@swift.org> 
>> wrote:
>>> On Dec 5, 2016, at 4:24 PM, Michael Gottesman via swift-dev 
>>> <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
>>> 
>>> 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.
> 
> Michael, does store_borrow go away if/when we eliminate the need for 
> different code patterns for direct vs. indirect arguments?

Yes.

> 
> John.

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

Reply via email to