[llvm] [AArch64][Windows] Fix swift async context slot placement (PR #212922)
Sébastien Marchand via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 31 14:46:49 PDT 2026
================
@@ -2858,8 +2852,7 @@ bool AArch64FrameLowering::assignCalleeSavedSpillSlots(
MFI.setIsCalleeSavedObjectIndex(FrameIdx, true);
// Grab 8 bytes below FP for the extended asynchronous frame info.
- if (hasFP(MF) && AFI->hasSwiftAsyncContext() && !IsWindows &&
- Reg == AArch64::FP) {
+ if (hasFP(MF) && AFI->hasSwiftAsyncContext() && Reg == AArch64::FP) {
FrameIdx = MFI.CreateStackObject(8, Alignment, true);
----------------
sebmarchand wrote:
It does change, 16 to 8. The Windows path passed `Align(16)` explicitly, the shared path uses `Alignment`, which is `getSpillAlign` for the register class.
It isn't really a separate change though, it's what falls out of dropping the Windows special case, and keeping 16 would mean adding a conditional back. I checked what that would cost: hard-coding `Align(16)` in the shared path changes macOS and Linux output, 14 of 110 runs over the swift tests across three triples, 38 changed lines on swift-async.ll for macos alone. With Alignment, non-Windows is byte identical to baseline. So the 8 is the conservative option, not the risky one.
I also tried the other direction, since a one-character fix would be nicer than moving the allocation: keep the original creation order and just pass `Align(8)`. That isn't enough, it does make the reported symptom go away, and on `swift-async-context-slot-offset-win.ll` it emits byte identical assembly to this patch, so it would pass the new test. But comparing MFI's recorded callee-save offsets against the addresses the prologue actually stores at, it still disagrees:
baseline 91 disagreements over 14 tests
Align(8) only 29 disagreements over 7 tests
this patch 0
On that one test the leftover is x21, MFI says sp+16 and the prologue stores at sp+8. Same shape of bug, it just stops landing on a saved register in that particular function. So the allocation really does have to move, the alignment on its own only hides it.
What the 16 was doing is visible in the frame table. The async slot is the object with no register attached.
```
Before, with [-24, -16) left unoccupied:
offset align register
-16 16 '' <- async context
-32 8 $lr
-40 8 $fp
-48 8 $x21
-56 8 $x19
After, contiguous:
offset align register
-16 16 $lr
-24 8 $fp
-32 8 '' <- async context
-40 8 $x21
-48 8 $x19
```
The slot's actual address doesn't move either way, sp+80 with fp at sp+88 in both, so FP-8 as required.
https://github.com/llvm/llvm-project/pull/212922
More information about the llvm-commits
mailing list