<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class="">Hi Raj,<div class=""><br class=""></div><div class="">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</div><div class=""><br class=""></div><div class="">@inline(never) internal func wrap_inc(a:SumProtocol, val:Int) -> Int{<br class=""> return a.increment(i:val)<br class="">}</div><div class=""><br class=""></div><div class="">Would become</div><div class=""><br class=""></div><div class="">@inline(always) internal func wrap_inc(a: SumProtocol, val: Int) -> Int {</div><div class=""> // opening an existential cannot be expressed in Swift, but it can in SIL…</div><div class=""> let _a = a open as T</div><div class=""><br class=""></div><div class=""> return _wrap_inc(_a, val)</div><div class="">}</div><div class=""><br class=""></div><div class="">@inline(never) internal func _wrap_inc<T : SumProtocol>(_a:T, val:Int) -> Int{</div><div class=""> let a: SomeProtocol = _a<br class=""> return a.increment(i:val)<br class="">}</div><div class=""><div><br class=""></div><div>(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.)</div><div><br class=""></div><div>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):</div><div><br class=""></div><div><div class="">@inline(always) internal func wrap_inc(a: SumProtocol, val: Int) -> Int {</div><div class=""> // opening an existential cannot be expressed in Swift, but it can in SIL…</div><div class=""> let _a = a open as T</div><div class=""><br class=""></div><div class=""> return _wrap_inc(_a, val)</div><div class="">}</div><div class=""><br class=""></div></div><div><div class="">@inline(never) internal func _wrap_inc<T : SumProtocol>(_a:T, val:Int) -> Int{</div><div class=""> return _a.increment(i:val)<br class="">}</div></div><div><br class=""></div><div>Now, if I have a call to wrap_inc somewhere, </div><div><br class=""></div><div>internal let magic:SumProtocol = SumClass(base:10)</div><div>_ = wrap_inc(magic)</div><div><br class=""></div><div>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.</div><div><br class=""></div><div>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.</div><div><br class=""></div><div>Slava</div><div><br class=""></div><div><blockquote type="cite" class=""><div class="">On Nov 29, 2017, at 11:30 AM, Raj Barik via swift-dev <<a href="mailto:swift-dev@swift.org" class="">swift-dev@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class=""><div style="font-size:12.8px" class=""><div class="">Hi,</div><div class=""><br class=""></div><div class="">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?</div><div class=""><br class=""></div><div class=""><div style="font-size:12.8px" class=""><b class="">Original code:</b></div></div><div class=""><b class=""><br class=""></b></div><div class=""><br class=""></div><div class="">protocol SumProtocol: class {</div><div class=""> func increment(i:Int) -> Int</div><div class="">}</div><div class=""><br class=""></div><div class="">internal class SumClass: SumProtocol {</div><div class=""> var a:Int</div><div class=""> init(base:Int) {</div><div class=""> self.a = base</div><div class=""> }</div><div class=""> func increment(i:Int) -> Int {</div><div class=""> self.a += i</div><div class=""> return self.a</div><div class=""> }</div><div class="">}</div><div class=""><br class=""></div><div class="">@inline(never) internal func wrap_inc(a:SumProtocol, val:Int) -> Int{</div><div class=""> return a.increment(i:val)</div><div class="">}</div><div class=""><br class=""></div><div class="">internal let magic:SumProtocol = SumClass(base:10)</div><div class="">print("c=\(wrap_inc(a:magic,<wbr class="">val:10))")</div></div><div style="font-size:12.8px" class=""><br class=""></div><div style="font-size:12.8px" class=""><br class=""></div><div style="font-size:12.8px" class=""><b class="">After Step 1:</b></div><div style="font-size:12.8px" class=""><br class=""></div><div style="font-size:12.8px" class=""><br class=""></div><div style="font-size:12.8px" class=""><div class="">protocol SumProtocol: class {</div><div class=""> func increment(i:Int) -> Int</div><div class="">}</div><div class=""><br class=""></div><div class="">internal class SumClass: SumProtocol {</div><div class=""> var a:Int</div><div class=""> init(base:Int) {</div><div class=""> self.a = base</div><div class=""> }</div><div class=""> func increment(i:Int) -> Int {</div><div class=""> self.a += i</div><div class=""> return self.a</div><div class=""> }</div><div class="">}</div><div class=""><br class=""></div><div class=""><div style="font-size:12.8px" class="">@inline(never) internal func wrap_inc(a:SumProtocol, val:Int) -> Int{</div><div style="font-size:12.8px" class=""> return a.increment(i:val)</div><div style="font-size:12.8px" class="">}</div></div><div class=""><br class=""></div><div class="">@inline(never) internal func wrap_inc_1(a:SumClass, val:Int) -> Int{</div><div class=""> return a.increment(i:val)</div><div class="">}</div><div class=""><br class=""></div><div class="">internal let magic:SumClass = SumClass(base:10)</div><div class="">print("c=\(wrap_inc_1(a:magic,<wbr class="">val:10))")</div></div><div style="font-size:12.8px" class=""><br class=""></div><div style="font-size:12.8px" class=""><br class=""></div><div style="font-size:12.8px" class=""><div class=""><b class="">After Step 2:</b></div><div class=""><b class=""><br class=""></b></div><div class=""><div class="">internal class SumClass {</div><div class=""> var a:Int</div><div class=""> init(base:Int) {</div><div class=""> self.a = base</div><div class=""> }</div><div class=""> func increment(i:Int) -> Int {</div><div class=""> self.a += i</div><div class=""> return self.a</div><div class=""> }</div><div class="">}</div><div class=""><br class=""></div><div class="">@inline(never) <span style="font-size:12.8px" class="">internal </span><span style="font-size:12.8px" class="">func wrap_inc(a:SumClass, val:Int) -> Int{</span></div><div class=""> return a.increment(i:val)</div><div class="">}</div><div class=""><br class=""></div><div class="">internal let magic:SumClass = SumClass(base:10)</div><div class="">print("c=\(wrap_inc(a:magic,<wbr class="">val:10))")</div></div></div><div style="font-size:12.8px" class=""><br class=""></div><div style="font-size:12.8px" class="">Any comments/thought on this transformation?</div><div style="font-size:12.8px" class=""><br class=""></div><div style="font-size:12.8px" class="">Best,</div><div style="font-size:12.8px" class="">Raj </div></div>
_______________________________________________<br class="">swift-dev mailing list<br class=""><a href="mailto:swift-dev@swift.org" class="">swift-dev@swift.org</a><br class="">https://lists.swift.org/mailman/listinfo/swift-dev<br class=""></div></blockquote></div><br class=""></div></body></html>