<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">This is a failure in the optimizer of identifying two loads to return the same value and so it can’t remove a retain/release pair.<div class=""><br class=""></div><div class=""><br class=""></div><div class="">/ protocol witness for B.foo(_:) in conformance OtherB<br class="">sil shared [transparent] [serialized] [thunk] @_T04test6OtherBCAA1BA2aDP3fooyAA1ACFTW&nbsp;: $@convention(witness_method) (@owned A, @in_guaranteed&nbsp;OtherB) -&gt; () {<br class="">// %0&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// user: %7<br class="">// %1&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// user: %3<br class="">bb0(%0 : $A, %1 : $*OtherB):<br class="">&nbsp;&nbsp;%2 = alloc_stack $OtherB&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// users: %9, %4, %11, %7<br class="">&nbsp;&nbsp;%3 = load %1 : $*OtherB&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// users: %6, %4<br class="">&nbsp;&nbsp;store %3 to %2 : $*OtherB&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// id: %4<br class="">&nbsp;&nbsp;// function_ref B.foo(_:)<br class="">&nbsp;&nbsp;%5 = function_ref @_T04test1BPAAE3fooyAA1ACF : $@convention(method) &lt;τ_0_0 where τ_0_0 : B&gt; (@owned A, @in_guaranteed τ_0_0) -&gt; () // user:&nbsp;%7<br class="">&nbsp;&nbsp;strong_retain %3 : $OtherB&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// id: %6<br class="">&nbsp;&nbsp;%7 = apply %5&lt;OtherB&gt;(%0, %2) : $@convention(method) &lt;τ_0_0 where τ_0_0 : B&gt; (@owned A, @in_guaranteed τ_0_0) -&gt; ()<br class="">&nbsp;&nbsp;%8 = tuple ()&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// user: %12<br class="">&nbsp;&nbsp;%9 = load %2 : $*OtherB&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// user: %10<br class="">&nbsp;&nbsp;strong_release %9 : $OtherB&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// id: %10<br class="">&nbsp;&nbsp;dealloc_stack %2 : $*OtherB&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// id: %11<br class="">&nbsp;&nbsp;return %8 : $()&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;// id: %12<br class="">} // end sil function ‘_T04test6OtherBCAA1BA2aDP3fooyAA1ACFTW’</div><div class=""><br class=""></div><div class="">If load store forwarding could just tell that the apply does not write to the alloc_stack &nbsp;(It could because @in_guaranteed guarantees no write) … i would expect it to mem promote this … ARC could then remove the retain/release pair (AFAICT).</div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><a href="https://bugs.swift.org/browse/SR-5403" class="">https://bugs.swift.org/browse/SR-5403</a></div><div class=""><br class=""></div><div class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Jul 7, 2017, at 11:27 AM, Johannes Weiß via swift-dev &lt;<a href="mailto:swift-dev@swift.org" class="">swift-dev@swift.org</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="">Hi swift-dev,<br class=""><br class="">If I have basically this program (full program see at the tail end of this mail)<br class=""><br class="">public class A { func bar() { ... }}<br class="">public protocol B {<br class=""> &nbsp;&nbsp;&nbsp;func foo(_ a: A)<br class="">}<br class="">extension B {<br class=""> &nbsp;&nbsp;&nbsp;func foo(_ a: A) { a.bar() }<br class="">}<br class="">public class ActualB: B {<br class="">}<br class="">public class OtherB: B {<br class="">}<br class="">func abc() {<br class=""> &nbsp;&nbsp;&nbsp;let b: B = makeB()<br class=""> &nbsp;&nbsp;&nbsp;b.foo(a)<br class="">}<br class=""><br class="">I get the following call frames when running it (compiled with `swiftc -O -g -o test test.swift`):<br class=""><br class=""> &nbsp;&nbsp;&nbsp;frame #1: 0x0000000100001dbf test`specialized A.bar() at test.swift:6 [opt]<br class=""> &nbsp;&nbsp;&nbsp;frame #2: 0x0000000100001e6f test`specialized B.foo(_:) [inlined] test.SubA.bar() -&gt; () at test.swift:0 [opt]<br class=""> &nbsp;&nbsp;&nbsp;frame #3: 0x0000000100001e6a test`specialized B.foo(a=&lt;unavailable&gt;) at test.swift:23 [opt]<br class=""> &nbsp;&nbsp;&nbsp;frame #4: 0x0000000100001a6e test`B.foo(_:) at test.swift:0 [opt]<br class=""> &nbsp;&nbsp;&nbsp;frame #5: 0x0000000100001b3e test`protocol witness for B.foo(_:) in conformance OtherB at test.swift:0 [opt]<br class=""> &nbsp;&nbsp;&nbsp;frame #6: 0x0000000100001ccd test`abc() at test.swift:45 [opt]<br class=""> &nbsp;&nbsp;&nbsp;frame #7: 0x0000000100001969 test`main at test.swift:48 [opt]<br class=""><br class="">1, 6, and 7 are obviously totally fine and expected.<br class=""><br class="">In 6 we are also building and destroying an existential box, also understandable and fine.<br class=""><br class="">But there's two things I don't quite understand:<br class=""><br class="">I) Why (in 5) will the existential container be retained and released?<br class=""><br class="">--- SNIP ---<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;__T04test6OtherBCAA1BA2aDP3fooyAA1ACFTW: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// protocol witness for test.B.foo(test.A) -&gt; () in conformance test.OtherB : test.B in test<br class="">0000000100001b20 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;push &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rbp &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;; CODE XREF=__T04test7ActualBCAA1BA2aDP3fooyAA1ACFTW+4<br class="">0000000100001b21 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rbp, rsp<br class="">0000000100001b24 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;push &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r14<br class="">0000000100001b26 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;push &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rbx<br class="">0000000100001b27 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r14, rdi<br class="">0000000100001b2a &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rbx, qword [r13]<br class="">0000000100001b2e &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rdi, rbx<br class="">0000000100001b31 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;call &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_swift_rt_swift_retain<br class="">0000000100001b36 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rdi, r14 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;; argument #1 for method __T04test1BPAAE3fooyAA1ACF<br class="">0000000100001b39 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;call &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;__T04test1BPAAE3fooyAA1ACF &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;; (extension in test):test.B.foo(test.A) -&gt; ()<br class="">0000000100001b3e &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rdi, rbx<br class="">0000000100001b41 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pop &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rbx<br class="">0000000100001b42 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pop &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r14<br class="">0000000100001b44 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pop &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rbp<br class="">0000000100001b45 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jmp &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_swift_rt_swift_release<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;; endp<br class="">--- SNAP ---<br class=""><br class="">II) Why are 2, 3, 4 and 5 not one stack frame? Seems like we could just JMP from one to the next. Sure in 5 the call is surrounded by a release/retain but in the others we could just JMP.<br class=""><br class=""><br class="">We see quite a measurable performance issue in a project we're working on (email me directly for details/code) and so I thought I'd ask because I'd like to understand why this is all needed (if it is).<br class=""><br class=""><br class="">Many thanks,<br class=""> &nbsp;Johannes<br class=""><br class="">--- SNIP ---<br class="">import Darwin<br class=""><br class="">public class A {<br class=""> &nbsp;&nbsp;&nbsp;@inline(never)<br class=""> &nbsp;&nbsp;&nbsp;public func bar() {<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print("bar")<br class=""> &nbsp;&nbsp;&nbsp;}<br class="">}<br class="">public class SubA: A {<br class=""> &nbsp;&nbsp;&nbsp;@inline(never)<br class=""> &nbsp;&nbsp;&nbsp;public override func bar() {<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print("bar")<br class=""> &nbsp;&nbsp;&nbsp;}<br class="">}<br class=""><br class="">public protocol B {<br class=""> &nbsp;&nbsp;&nbsp;func foo(_ a: A)<br class="">}<br class=""><br class="">public extension B {<br class=""> &nbsp;&nbsp;&nbsp;@inline(never)<br class=""> &nbsp;&nbsp;&nbsp;func foo(_ a: A) {<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a.bar()<br class=""> &nbsp;&nbsp;&nbsp;}<br class="">}<br class=""><br class="">public class ActualB: B {<br class="">}<br class=""><br class="">public class OtherB: B {<br class="">}<br class=""><br class="">public func makeB() -&gt; B {<br class=""> &nbsp;&nbsp;&nbsp;if arc4random() == 1231231 {<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return ActualB()<br class=""> &nbsp;&nbsp;&nbsp;} else {<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return OtherB()<br class=""> &nbsp;&nbsp;&nbsp;}<br class="">}<br class=""><br class="">@inline(never)<br class="">func abc() {<br class=""> &nbsp;&nbsp;&nbsp;let a = SubA()<br class=""> &nbsp;&nbsp;&nbsp;let b: B = makeB()<br class=""> &nbsp;&nbsp;&nbsp;b.foo(a)<br class="">}<br class=""><br class="">abc()<br class="">--- SNAP ---<br class=""><br class="">_______________________________________________<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></div></blockquote></div><br class=""></div></body></html>