mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
DestroyHoisting moves destroys of memory locations up the control flow as far as possible.
Beside destroy_addr, also "store [assign]" is considered a destroy, because is is equivalent to an destroy_addr + a "store [init]".
The main purpose of this optimization is to minimize copy-on-write operations for arrays, etc. Especially if such COW containers are used as enum payloads and modified in-place. E.g.
switch e {
case .A(var arr):
arr.append(x)
self = .A(arr)
...
In such a case DestroyHoisting can move the destroy of the self-assignment up before the switch and thus let the array buffer only be single-referenced at the time of the append.
When we have ownership SIL throughout the pass pipeline this optimization will replace the current destroy hoisting optimization in CopyForwarding.
For now, this optimization only runs in the mandatory pipeline (but not for -Onone) where we already have ownership SIL.
SR-10605
rdar://problem/50463362
116 lines
2.2 KiB
Swift
116 lines
2.2 KiB
Swift
// RUN: %empty-directory(%t)
|
|
// RUN: %target-build-swift -O -module-name=test %s -o %t/a.out
|
|
// RUN: %target-run %t/a.out | %FileCheck %s
|
|
|
|
// REQUIRES: executable_test,swift_stdlib_no_asserts,optimized_stdlib
|
|
|
|
final class Storage {
|
|
var v : Int
|
|
init(_ v : Int) {
|
|
self.v = v
|
|
}
|
|
}
|
|
|
|
struct IntBox {
|
|
var s : Storage
|
|
|
|
init(_ x : Int) {
|
|
s = Storage(x)
|
|
}
|
|
|
|
var value: Int { return s.v }
|
|
|
|
mutating func increment(_ delta: Int = 1) {
|
|
if (!isKnownUniquelyReferenced(&s)) {
|
|
// We should never see this message
|
|
print("## copy on write")
|
|
s = Storage(s.v)
|
|
}
|
|
s.v += delta
|
|
}
|
|
}
|
|
|
|
enum E: CustomStringConvertible {
|
|
case value(IntBox)
|
|
case none
|
|
|
|
@inline(never)
|
|
mutating func simpleIncrement() {
|
|
switch self {
|
|
case .value(var i):
|
|
i.increment()
|
|
self = .value(i)
|
|
case .none:
|
|
break
|
|
}
|
|
}
|
|
|
|
@inline(never)
|
|
mutating func incrementWithControlFlow(_ n: Int, _ c: Bool) {
|
|
switch self {
|
|
case .value(var i):
|
|
i.increment()
|
|
for _ in [0..<n] {
|
|
print(" loop iter")
|
|
}
|
|
if c {
|
|
i.increment(10)
|
|
self = .value(i)
|
|
} else {
|
|
i.increment(20)
|
|
self = .value(i)
|
|
}
|
|
case .none:
|
|
break
|
|
}
|
|
}
|
|
|
|
var description: String {
|
|
switch self {
|
|
case .value(let i):
|
|
return i.s.v.description
|
|
case .none:
|
|
return "none"
|
|
}
|
|
}
|
|
}
|
|
|
|
struct ContainingStruct {
|
|
var e: E = .value(IntBox(27))
|
|
|
|
@inline(never)
|
|
mutating func doSomething() {
|
|
switch self.e {
|
|
case .value(var i):
|
|
i.increment()
|
|
self.e = .value(i)
|
|
case .none:
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
// CHECK: simpleIncrement start
|
|
print("simpleIncrement start")
|
|
var e1 = E.value(IntBox(27))
|
|
e1.simpleIncrement()
|
|
// CHECK-NEXT: simpleIncrement end: 28
|
|
print("simpleIncrement end: \(e1)")
|
|
|
|
|
|
// CHECK-NEXT: incrementWithControlFlow start
|
|
print("incrementWithControlFlow start")
|
|
var e2 = E.value(IntBox(27))
|
|
// CHECK-NEXT: loop iter
|
|
e2.incrementWithControlFlow(1, true)
|
|
// CHECK-NEXT: incrementWithControlFlow end: 38
|
|
print("incrementWithControlFlow end: \(e2)")
|
|
|
|
// CHECK-NEXT: ContainingStruct start
|
|
print("ContainingStruct start")
|
|
var s = ContainingStruct()
|
|
s.doSomething()
|
|
// CHECK-NEXT: ContainingStruct end: 28
|
|
print("ContainingStruct end: \(s.e)")
|
|
|