[swift-dev] [arc optimization] Why doesn't enum destructuring use guaranteed references?

Félix Cloutier felixcloutier at icloud.com
Sat Dec 30 20:41:32 CST 2017


> Le 30 déc. 2017 à 14:22, Michael Gottesman <mgottesman at apple.com> a écrit :
>> That sounds fun. I'll have to check with my manager after the holidays.
> 
> Nerd snipe success? = p

I guess so? 🤓 I'm an easy target.

>> It sounds like having flexible parameter ownership rules doesn't have too much overhead if it can be user-specified (in some future). Would it be feasible to use escape analysis to decide if a parameter should be +0 or +1?
> 
> No. A parameter's convention is ABI. You don't want to change ABI related things like that via escape analysis since it means that as a function changes, due to the optimizer, the ABI can change =><=.

That makes sense, I hadn't thought about it.

> Cases like this are due to the optimizer seeing some use that it can not understand. The optimizer must be conservative so sometimes things that the user thinks the optimizer should see through/understand, it can not. The way to see that is to look at the SIL level and see what is stopping the code motion. There are ways that you can get debug output from the optimizer. This additionally may be a case where an opt-remark like system could help guide the user on why code motion has stopped.

My limited testing was basically checking this program:

> final class Foo {
> 	var bar = 4
> }
> 
> let instance = Foo()
> 
> @inline(never)
> func print(_ x: Int) {
> 	Swift.print(x)
> }
> 
> func main() {
> 	let foo = instance
> 	print(foo.bar)
> 	print(0)
> }


On my first pass I noticed that foo is released at the end of the function (hence the rest of my message), but upon closer inspection I see that it is, in fact, retained after `foo.bar` is accessed:

> sil hidden @_T04test4mainyyF : $@convention(thin) () -> () {
> bb0:
>   %0 = global_addr @_T04test8instanceAA3FooCv : $*Foo // user: %1
>   %1 = load %0 : $*Foo                            // users: %11, %6, %4, %2
>   debug_value %1 : $Foo, let, name "foo"          // id: %2
>   // function_ref print(_:)
>   %3 = function_ref @_T04test5printySiF : $@convention(thin) (Int) -> () // users: %10, %7
>   %4 = ref_element_addr %1 : $Foo, #Foo.bar       // user: %5
>   %5 = load %4 : $*Int                            // user: %7
>   strong_retain %1 : $Foo                         // id: %6
>   %7 = apply %3(%5) : $@convention(thin) (Int) -> ()
>   %8 = integer_literal $Builtin.Int64, 0          // user: %9
>   %9 = struct $Int (%8 : $Builtin.Int64)          // user: %10
>   %10 = apply %3(%9) : $@convention(thin) (Int) -> ()
>   strong_release %1 : $Foo                        // id: %11
>   %12 = tuple ()                                  // user: %13
>   return %12 : $()                                // id: %13
> } // end sil function '_T04test4mainyyF'


So while I thought earlier that I didn't know why it wasn't released, I guess that the better question is why it's retained at all!

>> I guess that the question is: what does Swift gain by keeping objects around for longer than they need to? Is it all about matching C++ or is there something else?
> 
> Again, I think you are extrapolating a bit. Swift is not attempting to keep objects around for longer than they need to be at all. Such situations are more likely due to optimizer inadequacies or unimplemented optimizations [again, nerd snipe alert, patches welcome ; )]. All of these things take engineering time to do and engineering time is something that must be prioritized with respect to the overall needs of the project.

Of course. I think that I was being a bit aggressive with "what is the benefit of this"; I knew there was a fair chance that it was "we had other things to do".

Félix



More information about the swift-dev mailing list