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)