You don’t need a second open_existential_ref in the _wrap_inc<T: SumProtocol> 
function. It should look something like this:

sil @_wrap_inc : $@convention(thin) <T where T : SumProtocol> (@owned T, Int) 
-> Int {
bb0(%0 : $T, %1 : $Int):
  %5 = witness_method $T, #SumProtocol.inc!1 : <Self where Self : SumProtocol> 
(Self) -> (Int) -> Int : $@convention(witness_method: SumProtocol) <τ_0_0 where 
τ_0_0 : SumProtocol> (Int, @guaranteed τ_0_0) -> Int
  %6 = apply %5<T>(%1, %0) : $@convention(witness_method: SumProtocol) <τ_0_0 
where τ_0_0 : SumProtocol> (Int, @guaranteed τ_0_0) -> Int
  destroy_value %0 : $T
  return %6 : $Int
}

In the other function it looks like you need to apply the proper substitution 
list to the apply instruction:

sil hidden [thunk] [always_inline] 
@_T04main8wrap_incSiAA11SumProtocol_p1a_Si3valtF : $@convention(thin) (@owned 
SumProtocol, Int) -> Int {
bb0(%0 : $SumProtocol, %1 : $Int):
  // function_ref specialized wrap_inc(a:val:)
  %2 = function_ref @_T04main8wrap_incSiAA11SumProtocol_p1a_Si3valtFTf4nn_n
  %3 = open_existential_ref %0 : $SumProtocol to 
$@opened("E6196082-DF72-11E7-8C84-420039484801") SumProtocol
  %4 = apply %2<τ_0_0>(%3, %1) : $@convention(thin) <τ_0_0 where τ_0_0 : 
SumProtocol> (@owned τ_0_0, Int) -> Int // user: %5

τ_0_0 should have been substituted by the opened type: 
$@opened("E6196082-DF72-11E7-8C84-420039484801”) SumProtocol.

  %3 = open_existential_ref %0 : $SumProtocol to 
$@opened("E6196082-DF72-11E7-8C84-420039484801") SumProtocol
  %4 = apply %2<@opened("E6196082-DF72-11E7-8C84-420039484801”) 
SumProtocol>(%3, %1) : $@convention(thin) <τ_0_0 where τ_0_0 : SumProtocol> 
(@owned τ_0_0, Int) -> Int


Probably, you have to pass the right SubstitutionList to the createApplyInst 
call. 


The peephole that propagates types from an init existential Slava referred to 
is here:

  
https://github.com/apple/swift/blob/master/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp#L974
 (SILCombiner::propagateConcreteTypeOfInitExistential)

Here is a test case that shows how the type from the init existential is 
propagated (instead of a generic type ’T’ as in the test case, in your case it 
would be the class type SumClass):
  
  
https://github.com/apple/swift/blob/master/test/SILOptimizer/sil_combine.sil#L2569

> On Dec 13, 2017, at 11:39 AM, Raj Barik via swift-dev <swift-dev@swift.org> 
> wrote:
> 
> Slava,
> 
> I have two (clarification) questions in your proposed implementation:
> 
> Original Function:
> @inline(never) internal func wrap_inc(a:SumProtocol, val:Int) -> Int{
>  return a.increment(i:val)
> }
> Transformed code:
> @inline(always) internal func wrap_inc(a: SumProtocol, val: Int) -> Int {
>   // opening an existential cannot be expressed in Swift, but it can in SIL…
>   let _a = a open as T
> 
>   return _wrap_inc(_a, val)
> }
> 
> @inline(never) internal func _wrap_inc<T : SumProtocol>(_a:T, val:Int) -> Int{
>  return _a.increment(i:val)
> }
> ****************************************************************************************
> In the above code sequence, did you mean that "let _a = a open as T" opens 
> "a:SumProtocol" using open_existential_ref  instruction as "SumClass" which 
> is the concrete type of a or it is opened as the "$@opened SumProtocol". In 
> both cases, the open_existential_ref in the original function is still there 
> and giving rise to opening the existential twice. Did you also intended that 
> the _wrap_inc function is rewritten to eliminate the open_existential_ref as 
> well (this is more complicated if the protocol is passed down a call chain)? 
> So, I do not really understand what the "let _a = a open as T" is suggesting. 
> The other part of the confusion is about the peephole optimization which 
> optimizes the code sequence consisting of the creation of object for SumClass 
> and then the init_existential_ref and followed by the open_existential_ref. 
> Can you clarify?
> 
> Thanks.
> 
> 
> On Wed, Nov 29, 2017 at 1:43 PM, Slava Pestov <spes...@apple.com> wrote:
> Hi Raj,
> 
> The way I would approach this problem is first, turn a function taking a 
> protocol value into one taking a protocol-constrained generic parameter. So
> 
> @inline(never) internal func wrap_inc(a:SumProtocol, val:Int) -> Int{
>  return a.increment(i:val)
> }
> 
> Would become
> 
> @inline(always) internal func wrap_inc(a: SumProtocol, val: Int) -> Int {
>   // opening an existential cannot be expressed in Swift, but it can in SIL…
>   let _a = a open as T
> 
>   return _wrap_inc(_a, val)
> }
> 
> @inline(never) internal func _wrap_inc<T : SumProtocol>(_a:T, val:Int) -> Int{
>  let a: SomeProtocol = _a
>  return a.increment(i:val)
> }
> 
> (Note that the existing function signature specialization pass performs a 
> similar transformation where it creates a new function with the same body as 
> the old function but a different signature, and replaces the old function 
> with a short thunk that transforms arguments and results and calls the new 
> function.)
> 
> At this point, the existing “initialize existential with concrete type” 
> peephole in the SILCombiner should eliminate the existential (but the 
> peephole doesn’t work in 100% of cases yet):
> 
> @inline(always) internal func wrap_inc(a: SumProtocol, val: Int) -> Int {
>   // opening an existential cannot be expressed in Swift, but it can in SIL…
>   let _a = a open as T
> 
>   return _wrap_inc(_a, val)
> }
> 
> @inline(never) internal func _wrap_inc<T : SumProtocol>(_a:T, val:Int) -> Int{
>  return _a.increment(i:val)
> }
> 
> Now, if I have a call to wrap_inc somewhere, 
> 
> internal let magic:SumProtocol = SumClass(base:10)
> _ = wrap_inc(magic)
> 
> Then the optimizer will inline the thunk, giving you a call to _wrap_inc. The 
> existential value built from the SumClass instance is immediately opened so 
> it will be peepholed away. At this point you have a call of a generic 
> function _wrap_inc with a concrete type SumClass, and the generic specializer 
> can produce a specialization of it.
> 
> Notice how this approach combines several existing optimizations and only 
> requires adding a relatively simple new transformation, and possibly 
> improving some of the existing optimizations to cover more cases.
> 
> Slava
> 
>> On Nov 29, 2017, at 11:30 AM, Raj Barik via swift-dev <swift-dev@swift.org> 
>> wrote:
>> 
>> Hi,
>> 
>> I am thinking about writing a Protocol Devirtualizer Pass that specializes 
>> functions that take Protocols as arguments to transform them with concrete 
>> types instead of protocol types when the concrete types can be determined 
>> statically by some compiler analysis. This is the first step of the 
>> transformation that I am proposing. My goal is to extend this to eliminate 
>> the original function implementation and also to remove the corresponding 
>> protocol type (by deleting it from the witness table), if possible. For 
>> simple cases, where the protocol is only used for mocking for example and 
>> that there is just one class that conforms to it, we should be able to 
>> eliminate the protocol altogether. This is the second and final step of the 
>> transformation. Does anyone see any issues with both these steps? Arnold 
>> from Apple pointed out that there might be demangling issues when the 
>> protocol is eliminated. Any ideas on how to fix the demangling issues? 
>> Moreover, would such a pass be helpful to Swift folks?
>> 
>> Original code:
>> 
>> 
>> protocol SumProtocol: class {
>>   func increment(i:Int)  -> Int
>> }
>> 
>> internal class SumClass: SumProtocol {
>>   var a:Int
>>   init(base:Int) {
>>     self.a = base
>>   }
>>   func increment(i:Int) -> Int {
>>    self.a += i
>>    return self.a
>>   }
>> }
>> 
>> @inline(never) internal func wrap_inc(a:SumProtocol, val:Int) -> Int{
>>  return a.increment(i:val)
>> }
>> 
>> internal let magic:SumProtocol = SumClass(base:10)
>> print("c=\(wrap_inc(a:magic,val:10))")
>> 
>> 
>> After Step 1:
>> 
>> 
>> protocol SumProtocol: class {
>>   func increment(i:Int)  -> Int
>> }
>> 
>> internal class SumClass: SumProtocol {
>>   var a:Int
>>   init(base:Int) {
>>     self.a = base
>>   }
>>   func increment(i:Int) -> Int {
>>    self.a += i
>>    return self.a
>>   }
>> }
>> 
>> @inline(never) internal func wrap_inc(a:SumProtocol, val:Int) -> Int{
>>  return a.increment(i:val)
>> }
>> 
>> @inline(never) internal func wrap_inc_1(a:SumClass, val:Int) -> Int{
>>  return a.increment(i:val)
>> }
>> 
>> internal let magic:SumClass = SumClass(base:10)
>> print("c=\(wrap_inc_1(a:magic,val:10))")
>> 
>> 
>> After Step 2:
>> 
>> internal class SumClass {
>>   var a:Int
>>   init(base:Int) {
>>     self.a = base
>>   }
>>   func increment(i:Int) -> Int {
>>    self.a += i
>>    return self.a
>>   }
>> }
>> 
>> @inline(never) internal func wrap_inc(a:SumClass, val:Int) -> Int{
>>  return a.increment(i:val)
>> }
>> 
>> internal let magic:SumClass = SumClass(base:10)
>> print("c=\(wrap_inc(a:magic,val:10))")
>> 
>> Any comments/thought on this transformation?
>> 
>> Best,
>> Raj 
>> _______________________________________________
>> swift-dev mailing list
>> swift-dev@swift.org
>> https://lists.swift.org/mailman/listinfo/swift-dev
> 
> 
> _______________________________________________
> swift-dev mailing list
> swift-dev@swift.org
> https://lists.swift.org/mailman/listinfo/swift-dev

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

Reply via email to