Skip to content

[6.0 cherry-pick][embedded] Consider move_value/copy_value as removable for keypath optimization #73214

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,19 @@ extension KeyPathInst : OnoneSimplifyable {
fileprivate func allUsesRemovable(instruction: Instruction) -> Bool {
for result in instruction.results {
for use in result.uses {
if !(use.instruction is UpcastInst || use.instruction is DestroyValueInst || use.instruction is BeginBorrowInst || use.instruction is EndBorrowInst) {
return false
}
if !allUsesRemovable(instruction: use.instruction) {
switch use.instruction {
case is UpcastInst,
is DestroyValueInst,
is BeginBorrowInst,
is EndBorrowInst,
is MoveValueInst,
is CopyValueInst:
// This is a removable instruction type, continue descending into uses
if !allUsesRemovable(instruction: use.instruction) {
return false
}

default:
return false
}
}
Expand Down
43 changes: 43 additions & 0 deletions test/embedded/keypaths2.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// RUN: %target-run-simple-swift( -enable-experimental-feature Embedded -wmo -runtime-compatibility-version none) | %FileCheck %s
// RUN: %target-run-simple-swift(-O -enable-experimental-feature Embedded -wmo -runtime-compatibility-version none) | %FileCheck %s

// REQUIRES: swift_in_compiler
// REQUIRES: executable_test
// REQUIRES: optimized_stdlib
// REQUIRES: OS=macosx || OS=linux-gnu

@dynamicMemberLookup
public struct Box<T>: ~Copyable {
init() {
self.value = UnsafeMutablePointer<T>.allocate(capacity: 1)
}

subscript<U>(dynamicMember member: WritableKeyPath<T, U>) -> U {
@_transparent
get { return self.value.pointer(to: member)!.pointee }

@_transparent
set { self.value.pointer(to: member)!.pointee = newValue }
}

var value: UnsafeMutablePointer<T>
}

public struct Foo {
var a: Int
var b: Int
}

public func test_read(x: inout Box<Foo>) -> Int {
return x.b
}

public func test_write(x: inout Box<Foo>) {
x.b = 42
}

var box = Box<Foo>()
_ = test_read(x: &box)
test_write(x: &box)
print(box.b)
// CHECK: 42
64 changes: 64 additions & 0 deletions test/embedded/keypaths3.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// RUN: %target-run-simple-swift( -enable-experimental-feature Embedded -wmo -Xfrontend -disable-access-control -runtime-compatibility-version none) | %FileCheck %s
// RUN: %target-run-simple-swift(-O -enable-experimental-feature Embedded -wmo -Xfrontend -disable-access-control -runtime-compatibility-version none) | %FileCheck %s

// REQUIRES: swift_in_compiler
// REQUIRES: executable_test
// REQUIRES: optimized_stdlib
// REQUIRES: OS=macosx || OS=linux-gnu

@dynamicMemberLookup
public struct Box<T>: ~Copyable {
internal init(from t: T) {
self.value = UnsafeMutablePointer<InnerBox<T>>.allocate(capacity: 1)
self.value.pointee = .init(t)
}

public subscript<Value>(dynamicMember member: WritableKeyPath<InnerBox<T>, Value>) -> Value
{
@_transparent
@inline(__always)
get { return self.value.pointer(to: member)!.pointee }

@_transparent
@inline(__always)
set { self.value.pointer(to: member)!.pointee = newValue }
}

public struct InnerBox<V> {
public init(_ value: V) { self.innerValue = value }
public var innerValue: V
}

@usableFromInline
internal var value: UnsafeMutablePointer<InnerBox<T>>
}

struct Foo {
var a: Int
var b: Int
}

@inline(never)
public func test() -> Int {
var x = Box<Foo>(from: Foo(a: 0, b: 0))
x.innerValue.b = 42
return x.innerValue.b
}

precondition(test() == 42)
print("OK!")
// CHECK: OK!

public func test_read(x: inout Box<Foo>) -> Int {
return x.innerValue.b
}

public func test_write(x: inout Box<Foo>) {
x.innerValue.b = 42
}

var box = Box<Foo>(from: Foo(a: 0, b: 0))
_ = test_read(x: &box)
test_write(x: &box)
print(box.innerValue.b)
// CHECK: 42