Skip to content

Commit 2e5812b

Browse files
committed
[embedded] Consider move_value/copy_value as removable for keypath optimization
1 parent 96d05ec commit 2e5812b

File tree

3 files changed

+120
-4
lines changed

3 files changed

+120
-4
lines changed

SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyKeyPath.swift

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,19 @@ extension KeyPathInst : OnoneSimplifyable {
3131
fileprivate func allUsesRemovable(instruction: Instruction) -> Bool {
3232
for result in instruction.results {
3333
for use in result.uses {
34-
if !(use.instruction is UpcastInst || use.instruction is DestroyValueInst || use.instruction is BeginBorrowInst || use.instruction is EndBorrowInst) {
35-
return false
36-
}
37-
if !allUsesRemovable(instruction: use.instruction) {
34+
switch use.instruction {
35+
case is UpcastInst,
36+
is DestroyValueInst,
37+
is BeginBorrowInst,
38+
is EndBorrowInst,
39+
is MoveValueInst,
40+
is CopyValueInst:
41+
// This is a removable instruction type, continue descending into uses
42+
if !allUsesRemovable(instruction: use.instruction) {
43+
return false
44+
}
45+
46+
default:
3847
return false
3948
}
4049
}

test/embedded/keypaths2.swift

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// RUN: %target-run-simple-swift( -enable-experimental-feature Embedded -wmo -runtime-compatibility-version none) | %FileCheck %s
2+
// RUN: %target-run-simple-swift(-O -enable-experimental-feature Embedded -wmo -runtime-compatibility-version none) | %FileCheck %s
3+
4+
// REQUIRES: swift_in_compiler
5+
// REQUIRES: executable_test
6+
// REQUIRES: optimized_stdlib
7+
// REQUIRES: OS=macosx || OS=linux-gnu
8+
9+
@dynamicMemberLookup
10+
public struct Box<T>: ~Copyable {
11+
init() {
12+
self.value = UnsafeMutablePointer<T>.allocate(capacity: 1)
13+
}
14+
15+
subscript<U>(dynamicMember member: WritableKeyPath<T, U>) -> U {
16+
@_transparent
17+
get { return self.value.pointer(to: member)!.pointee }
18+
19+
@_transparent
20+
set { self.value.pointer(to: member)!.pointee = newValue }
21+
}
22+
23+
var value: UnsafeMutablePointer<T>
24+
}
25+
26+
public struct Foo {
27+
var a: Int
28+
var b: Int
29+
}
30+
31+
public func test_read(x: inout Box<Foo>) -> Int {
32+
return x.b
33+
}
34+
35+
public func test_write(x: inout Box<Foo>) {
36+
x.b = 42
37+
}
38+
39+
var box = Box<Foo>()
40+
_ = test_read(x: &box)
41+
test_write(x: &box)
42+
print(box.b)
43+
// CHECK: 42

test/embedded/keypaths3.swift

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// RUN: %target-run-simple-swift( -enable-experimental-feature Embedded -wmo -Xfrontend -disable-access-control -runtime-compatibility-version none) | %FileCheck %s
2+
// RUN: %target-run-simple-swift(-O -enable-experimental-feature Embedded -wmo -Xfrontend -disable-access-control -runtime-compatibility-version none) | %FileCheck %s
3+
4+
// REQUIRES: swift_in_compiler
5+
// REQUIRES: executable_test
6+
// REQUIRES: optimized_stdlib
7+
// REQUIRES: OS=macosx || OS=linux-gnu
8+
9+
@dynamicMemberLookup
10+
public struct Box<T>: ~Copyable {
11+
internal init(from t: T) {
12+
self.value = UnsafeMutablePointer<InnerBox<T>>.allocate(capacity: 1)
13+
self.value.pointee = .init(t)
14+
}
15+
16+
public subscript<Value>(dynamicMember member: WritableKeyPath<InnerBox<T>, Value>) -> Value
17+
{
18+
@_transparent
19+
@inline(__always)
20+
get { return self.value.pointer(to: member)!.pointee }
21+
22+
@_transparent
23+
@inline(__always)
24+
set { self.value.pointer(to: member)!.pointee = newValue }
25+
}
26+
27+
public struct InnerBox<V> {
28+
public init(_ value: V) { self.innerValue = value }
29+
public var innerValue: V
30+
}
31+
32+
@usableFromInline
33+
internal var value: UnsafeMutablePointer<InnerBox<T>>
34+
}
35+
36+
struct Foo {
37+
var a: Int
38+
var b: Int
39+
}
40+
41+
@inline(never)
42+
public func test() -> Int {
43+
var x = Box<Foo>(from: Foo(a: 0, b: 0))
44+
x.innerValue.b = 42
45+
return x.innerValue.b
46+
}
47+
48+
precondition(test() == 42)
49+
print("OK!")
50+
// CHECK: OK!
51+
52+
public func test_read(x: inout Box<Foo>) -> Int {
53+
return x.innerValue.b
54+
}
55+
56+
public func test_write(x: inout Box<Foo>) {
57+
x.innerValue.b = 42
58+
}
59+
60+
var box = Box<Foo>(from: Foo(a: 0, b: 0))
61+
_ = test_read(x: &box)
62+
test_write(x: &box)
63+
print(box.innerValue.b)
64+
// CHECK: 42

0 commit comments

Comments
 (0)