Open nocchijiang opened 11 months ago
In this case foo
is not a struct, it is an existential whose underlying type we have no idea about. If S
were generic over Foo
it could specialize the function and only need to copy it once (via a retain).
In this case
foo
is not a struct, it is an existential whose underlying type we have no idea about.
IIUC, you mean this is part of the price we have to pay by using existential? The side effect of using an existential in a slightly complex binary expression is to implicitly copy it? This doesn't sound right to me.
If I understand correctly, we have copies here
func bar() -> Void {
if self.foo.foo(Int.random(in: 0..<100)) || self.foo.foo(Int.random(in: 1..<10)) || self.foo.foo(Int.random(in: 2..<1000)) {
print("hello")
}
}
but here - not?
func bar() -> Void {
let c1 = self.foo.foo(Int.random(in: 0..<100))
let c2 = self.foo.foo(Int.random(in: 1..<10))
let c3 = self.foo.foo(Int.random(in: 2..<1000))
if c1 || c2 || c3 {
print("hello")
}
}
@skyien Yes, in the second code snippet, the calls to foo
are moved out of the binary expression. My understanding of the issue is that:
CC: @eeckstein @nate-chandler
cc @atrick
The copy_addr is already generated by SILGen. But okay, SILGen is not very smart.
But it should be easily possible for CopyForwarding to eliminate the copy because the destination is either used by an @in_guaranteed
partial-apply argument or by an open_existential_addr immutable_access
I found another bad case in production that self
gets copied but I cannot reproduce it in a complete demo (I don't know how to make an address-only struct
in the demo - I have confirmed that this is one of the necessary conditions). In the foo
getter, self
is being copied in foo
multiple times if AHugeStruct
is address-only.
struct AHugeStruct {
let anEnum: AnEnum
var foo: Bool {
return anEnum != .caseA &&
anEnum != .caseB &&
anEnum != .caseC &&
anEnum != .caseD
}
}
@nocchijiang to make a struct address only, you can
struct AHugeStruct<T> { var t: T }
Description A
struct
is copied if it is used in the condition expression of anif
statement multiple times.Steps to reproduce
To compile the demo:
In the generated code, the "outlined init with copy of
Foo
" is called inS.bar()
multiple times.Expected behavior The
foo
struct should not be copied except for thelet
binding inS.bar()
.Environment I have tested and confirmed this behavior exists on both Xcode 15.0.1 and the trunk development snapshot. Initially this issue was found in an iOS app, I made a minimum-reproducible demo for the issue report.