I'm filing this under compiler because I get different results between -Onone
and -O
. It might be an issue with the soon-to-be-deprecated swift-atomics
package but my guess is otherwise.
The offending code is:
import Atomics
func inner(_ group: inout TaskGroup<Void>) async -> ManagedAtomic<Int> {
let count = ManagedAtomic<Int>(314) // guard value
for _ in 0..<10 {
group.addTask { count.wrappingIncrement(ordering: .relaxed) }
}
return count
}
func outer1() async -> Int {
async let count = withTaskGroup(of: Void.self, body: inner)
return await count.load(ordering: .relaxed)
}
func outer2() async -> Int {
let count = await withTaskGroup(of: Void.self, body: inner)
return count.load(ordering: .relaxed)
}
await print(outer1(), outer2())
While I'm using .relaxed
loads and stores, there is a data dependency between outer1() / outer2()
and inner()
: neither outer func can know what address to load the atomic value from until withTaskGroup
returns which is documented as:
When compiled with -Onone
, I get the expected result: 324, 324
With -O
or -Osize
, the result is a worrying 324, 0 on both x86 and M1
It seems that in optimized builds, when not using async let
, the atomic value is loaded not just before the return of withTaskGroup()
, but before it was initialized to its 314
guard value.
Version 15.2 (15C500b)