Skip to content
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

[SR-11895] Optimiser should be able to observe when a program could have used the _modify accessor #54312

Open
Lukasa opened this issue Dec 4, 2019 · 1 comment
Labels
compiler The Swift compiler in itself improvement performance

Comments

@Lukasa
Copy link
Contributor

Lukasa commented Dec 4, 2019

Previous ID SR-11895
Radar rdar://problem/57711767
Original Reporter @Lukasa
Type Improvement
Additional Detail from JIRA
Votes 1
Component/s Compiler
Labels Improvement, Performance
Assignee None
Priority Medium

md5: 79e96d8a1b91323cc0428090f3176d7a

Issue Description:

In programs using CoW data structures, the _modify accessor can be the difference between a program that performs fantastically well and one that performs very poorly. Unfortunately, getting Swift to actually use the _modify accessor is deeply non-obvious: in practice, _modify will only be used when the load/store operation is expressible in one line. The actual logic may be arbitrarily complex (for example, calling a very complex mutating function, i.e. array[index].myVeryComplexMutatingFunction(), but the point of invocation of that operation must be expressed in one line.

I suspect substantial performance wins would be available in naive programs if the optimiser could observe that the _modify accessor could have been used. For example, consider the following program:

struct Test {
    private var backing: Int = 0

    var test: Int {
        get {
            print("\tget")
            return self.backing
        }
        set {
            print("\tset")
            self.backing = newValue
        }
        _modify {
            print("\tget modify")
            yield &self.backing
            print("\tset modify")
        }
    }
}

@discardableResult
func easy() -> Int {
    print("easy")
    var t = Test()
    t.test += 5
    return t.test
}

@discardableResult
func hard() -> Int {
    print("hard")
    var t = Test()
    var temp = t.test
    temp += 5
    t.test = temp
    return t.test
}

@discardableResult
func setOnly() -> Int {
    print("setOnly")
    var t = Test()
    t.test = 5
    return t.test
}

easy()
hard()
setOnly()

When executed with -O, this program will print:

easy
    get modify
    set modify
    get
hard
    get
    set
    get
setOnly
    set
    get

which indicates that only the direct mutation actually uses the _modify accessor.

That's very disappointing! Some analysis of the ownership of t in the hard case should observe that no operation between the load and the store either modifies or copies t. As a result, we can behave as if t were exclusively owned during the entire intervening period, and replace the get/set with a _modify.

I don't know how hard this work would be, but it has the potential to make a bunch of programs substantially faster, as well as to remove a "one weird trick to make your programs fast" wart that Swift currently has.

@beccadax
Copy link
Contributor

beccadax commented Dec 6, 2019

@swift-ci create

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler The Swift compiler in itself improvement performance
Projects
None yet
Development

No branches or pull requests

2 participants