As in most languages on most CPU architectures, there's no guarantee of ordering between writes to a and b, nor c and d. If you're seeing ordering it's just happenstance of the CPU you're executing it on¹.
Your first closure compiles down to (on AArch64):
ldp x8, x9, [x20, #0x10]
mov w10, #0xa
str x10, [x8, #0x10]
mov w8, #0x14
str x8, [x9, #0x10]
ret
No barrier instructions or anything like that.
The second closure has a bit more boilerplate, for loading the closure's context and finding the address of the heap-allocated values, but it's essentially:
ldr x9, [x9, #0x10]
str x9, [x8, #0x10]
ldr x8, [x11, #0x10]
str x8, [x10, #0x10]
Again, no barriers of any kind (in these closures themselves - GCD likely emits full barriers between blocks).
AArch64 only guarantees a particular apparent² order of memory accesses when any of:
- There is a data dependency between the two accesses (e.g. the first writes to an address, the second reads from it).
- There is an address dependency between the two accesses (e.g. the first one reads a pointer value from memory, the second reads from the pointed-to address).
- There is a control dependency between the two accesses (e.g. the first one is checked for equality to zero and the second is conditionalised on the result).
- There is a relevant barrier instruction between them (e.g.
dmb).
¹ CPU's don't have to reorder things, of course, and even modern CPUs might be somewhat if not entirely in-order if their priority is energy efficiency. Though the compiler is still free to reorder instructions. LLVM seems to avoid re-ordering unless there's a clear reason for it, although it'd be entirely within spec to literally reorder independent operations randomly for the hell of it. I don't know if swiftc / LLVM has a mode to do this, but it'd be useful if it did for fuzz-testing for missing barriers.
² Technically the CPU is free to do whatever it wants as long as it presents the appearance of obeying these rules. e.g. it might speculatively read something out of order, or guess what the read value will be, and only redo the read if it turns out it guessed wrong.