For a function foo(x: SomeClass) that we defined, is there a Swift level annotation (e.g. attribute) that we can use to make x @owned instead of @guaranteed?
Yes, and it's currently spelled __owned. It will need to go through Evolution before it becomes source-stable, of course (i.e. lose the underscores and possibly get a new name).
Thanks!
SomeClass is a class that we defined. Is there a way to guarantee that a SomeClass-typed value is always consumed at +0, and never +1?
Why would you want this at the type level? If it's for your code-motion rebalancing, I think the semantic-SIL efforts to use copy_value / destroy_value instead of retain_value / release_value will be the right solution instead of trying to pretend that references can never meaningfully have their ownership transferred between contexts. The invariants that that rule establishes are the invariants you want for your "refcount bias" verification.
The SILGen-created code already has retain/release insts. e.g. With the old convention where @foo() takes param x at +1 (@owned), the original SIL pseudo-code can be:
%x = SomeClass(...)
strong_retain %x
%y = foo(%x)
strong_release %x // x is destroyed here
<code chunk 1>
<code chunk 2>
Since foo() takes +1 and returns +1, we can move foo() below, as in:
%x = SomeClass(...)
strong_retain %x
strong_release %x
<code chunk 1>
%y = foo(%x) // x is destroyed here
<code chunk 2>
With the new param convention of @guaranteed, the original SIL code becomes:
%x = SomeClass(...)
strong_retain %x
%y = foo(%x)
strong_release %x // extra strong_release here compared to above
strong_release %x // x is destroyed here
<code chunk 1>
<code chunk 2>
Now we cannot simply move down foo(%x). One option is to make sure when foo(%x) gets moved down, we move down a subsequent strong_release accordingly, but that is somewhat more complexity.
How can I use copy_value / destroy_value in the above case to simplify the design?
BTW, I don't know why the SILGen-generated code in the new case is not:
%x = SomeClass(...)
%y = foo(%x)
strong_release %x // x is destroyed here
<code chunk 1>
<code chunk 2>
But that seems a minor issue at this point and a later peephole pass can in theory clean it up.