Skip to content

Optimizer not removing MainActor checks when calling into non-escaping closure #82538

Open
@harlanhaskins

Description

@harlanhaskins

Description

Godbolt link showing the suboptimal codegen:

https://godbolt.org/z/cxMETnnWv

This also still reproduces with NonisolatedNonsendingByDefault enabled:

https://godbolt.org/z/4b9K3M6nv

Reproduction

The following code:

@MainActor
final class MyClass {
    var items: [Int] = []

    func isEven(_ number: Int) -> Bool {
        number.isMultiple(of: 2)
    }

    func numberOfEvens() -> Int {
        items.count {
            self.isEven($0)
        }
    }
}

Causes each iteration of the inlined inner loop from count(where:) to still check the executor at runtime to make sure we're on the main actor when calling into self.isEven.

Unfortunately the Typo app is seeing large amounts of time, sometimes upwards of 30% of frame execution time, spent dynamically checking the main actor executor.

Expected behavior

I would expect the compiler to recognize from the fact that count(where:)'s closure is non-escaping and synchronous that it will not escape the main actor, and therefore it should be able to deterministically elide runtime checks.

Environment

swift-driver version: 1.127.4.2 Apple Swift version 6.2 (swiftlang-6.2.0.9.909 clang-1700.3.9.907)
Target: arm64-apple-macosx26.0

Additional information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugA deviation from expected or documented behavior. Also: expected but undesirable behavior.run-time performance

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions