[swift-dev] Proposal: SILValue SSA Instructions
    Michael Gottesman 
    mgottesman at apple.com
       
    Mon Dec  5 18:24:46 CST 2016
    
    
  
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.
----
    
    
More information about the swift-dev
mailing list