Re: [swift-dev] COW for non-mutating methods

2016-12-01 Thread Joe Groff via swift-dev

> On Dec 1, 2016, at 3:29 AM, Patrick Pijnappel via swift-dev 
>  wrote:
> 
> I'm implementing a COW big int type but am running into problems with 
> non-mutating functions (e.g. the + operator). Simplified example code below 
> shows AFAIK the default way to implement COW, but the non-mutating method 
> doesn't identify the reference as unique (even with -O), resulting in a 
> needless copy.
> 
> I've tried everything I could think of, but only inout parameters seem to 
> work. How does the standard library do this, for e.g. String + String?

> 
> struct Foo {
>   var storage = Storage()
> 
>   class Storage { var x = 0 }
> 
>   init(_ x: Int) { storage.x = x }
> 
>   mutating func negate() {
> if !isKnownUniquelyReferenced() {
>   print("Copy")
> }
> storage.x = -storage.x
>   }
> 
>   func negated() -> Foo {
> var result = self // This counts as a second reference
> result.negate()
> return result
>   }
> }
> 
> func test() {
>   var a = Foo(5)
>   a.negate()
>   print(a.storage.x)
> 
>   let b = Foo(5)
>   let c = b.negated()
>   print(c.storage.x)
> }
> 
> test()

Unfortunately, the compiler currently always passes the 'self' parameter of a 
nonmutating method with a caller-release convention, meaning that any local 
mutable copy necessarily needs to retain a local copy and can't consume the 
incoming 'self' value, and there's currently no way to override this. 
Theoretically, defining `negated` as a free function should enable this 
optimization, since non-'self' parameters are passed callee-release and can be 
consumed:

func negate(foo: Foo) -> Foo {
  var result = foo
  result.negate()
  return result
}

though from what I've seen, the ARC optimizer doesn't always successfully 
shorten the lifetime of parameters enough to turn the "result = foo" into a 
move, which is a known bug.

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


[swift-dev] COW for non-mutating methods

2016-12-01 Thread Patrick Pijnappel via swift-dev
I'm implementing a COW big int type but am running into problems with
non-mutating functions (e.g. the + operator). Simplified example code below
shows AFAIK the default way to implement COW, but the non-mutating method
doesn't identify the reference as unique (even with -O), resulting in a
needless copy.

I've tried everything I could think of, but only inout parameters seem to
work. How does the standard library do this, for e.g. String + String?


struct Foo {

  var storage = Storage()


  class Storage { var x = 0 }


  init(_ x: Int) { storage.x = x }


  mutating func negate() {

if !isKnownUniquelyReferenced() {

  print("Copy")

}

storage.x = -storage.x

  }


  func negated() -> Foo {

var result = self // This counts as a second reference

result.negate()

return result

  }

}


func test() {

  var a = Foo(5)

  a.negate()

  print(a.storage.x)


  let b = Foo(5)

  let c = b.negated()

  print(c.storage.x)

}


test()



*Output*

-5

Copy

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