Skip to content

[SR-14480] Function signature optimization turns __consuming method back into guaranteed, breaking in-place optimization opportunity #56836

@jckarter

Description

@jckarter
Previous ID SR-14480
Radar rdar://problem/76603842
Original Reporter @jckarter
Type Bug
Additional Detail from JIRA
Votes 0
Component/s Compiler
Labels Bug
Assignee None
Priority Medium

md5: 925e966143b77f5dd462576199b5f62d

Issue Description:

I was testing out the effects of copy forwarding on the following code:

class NoisyCowBuffer {
    var value: Int
    init(value: Int) {
        print("moo")
        self.value = value
    }
}

struct NoisyCow: CustomStringConvertible {
    var buffer: NoisyCowBuffer

    init(value: Int) {
        buffer = NoisyCowBuffer(value: value)
    }

    mutating func increment() {
        if isKnownUniquelyReferenced(&buffer) {
            buffer.value += 1
        } else {
            buffer = NoisyCowBuffer(value: buffer.value + 1)
        }
    }

    @inline(never)
    __consuming func incremented() -> NoisyCow {
        var myself = self
        myself.increment()
        return myself
    }

    var description: String { "NoisyCow(value: \(buffer.value))" }
}

do {
    let cow = NoisyCow(value: 0)
    _ = cow.incremented().incremented().incremented()
}

expecting there to only be one `moo` printed, since the single copy of `cow` ought to be forwarded +1 through all the `__consuming` calls to `incremented`. However, function signature optimization for some reason decides that `incremented` would be better handled as `guaranteed` and undoes the manual optimization. With `swiftc -O -emit-sil` I get:

// NoisyCow.incremented()
sil hidden [signature_optimized_thunk] [always_inline] @$s3foo8NoisyCowV11incrementedACyF : $@conven
tion(method) (@owned NoisyCow) -> @owned NoisyCow {
// %0 "self"                                      // users: %3, %2
bb0(%0 : $NoisyCow):
  // function_ref specialized NoisyCow.incremented()
  %1 = function_ref @$s3foo8NoisyCowV11incrementedACyFTf4g_n : $@convention(thin) (@guaranteed Noisy
Cow) -> @owned NoisyCow // user: %2
  %2 = apply %1(%0) : $@convention(thin) (@guaranteed NoisyCow) -> @owned NoisyCow // user: %4
  release_value %0 : $NoisyCow                    // id: %3
  return %2 : $NoisyCow                           // id: %4
} // end sil function '$s3foo8NoisyCowV11incrementedACyF'

and multiple `moo`s printed at runtime.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugA deviation from expected or documented behavior. Also: expected but undesirable behavior.compilerThe Swift compiler itself

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions