Skip to content

Commit 0c9f909

Browse files
MacDuetstellar
authored andcommitted
[AArch64][SME] Fix restoring callee-saves from FP with hazard padding (#143371)
Currently, when hazard-padding is enabled a (fixed-size) hazard slot is placed in the CS area, just after the frame record. The size of this slot is part of the "CalleeSaveBaseToFrameRecordOffset". The SVE epilogue emission code assumed this offset was always zero, and incorrectly setting the stack pointer, resulting in all SVE registers being reloaded from incorrect offsets. ``` | prev_lr | | prev_fp | | (a.k.a. "frame record") | |-----------------------------------| <- fp(=x29) | <hazard padding> | |-----------------------------------| <- callee-saved base | | | callee-saved fp/simd/SVE regs | | | |-----------------------------------| <- SVE callee-save base ``` i.e. in the above diagram, the code assumed `fp == callee-saved base`.
1 parent fa792cd commit 0c9f909

File tree

2 files changed

+1198
-12
lines changed

2 files changed

+1198
-12
lines changed

llvm/lib/Target/AArch64/AArch64FrameLowering.cpp

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2501,20 +2501,33 @@ void AArch64FrameLowering::emitEpilogue(MachineFunction &MF,
25012501

25022502
// Deallocate the SVE area.
25032503
if (SVEStackSize) {
2504-
// If we have stack realignment or variable sized objects on the stack,
2505-
// restore the stack pointer from the frame pointer prior to SVE CSR
2506-
// restoration.
2507-
if (AFI->isStackRealigned() || MFI.hasVarSizedObjects()) {
2508-
if (int64_t CalleeSavedSize = AFI->getSVECalleeSavedStackSize()) {
2509-
// Set SP to start of SVE callee-save area from which they can
2510-
// be reloaded. The code below will deallocate the stack space
2511-
// space by moving FP -> SP.
2512-
emitFrameOffset(MBB, RestoreBegin, DL, AArch64::SP, AArch64::FP,
2513-
StackOffset::getScalable(-CalleeSavedSize), TII,
2504+
int64_t SVECalleeSavedSize = AFI->getSVECalleeSavedStackSize();
2505+
// If we have stack realignment or variable-sized objects we must use the
2506+
// FP to restore SVE callee saves (as there is an unknown amount of
2507+
// data/padding between the SP and SVE CS area).
2508+
Register BaseForSVEDealloc =
2509+
(AFI->isStackRealigned() || MFI.hasVarSizedObjects()) ? AArch64::FP
2510+
: AArch64::SP;
2511+
if (SVECalleeSavedSize && BaseForSVEDealloc == AArch64::FP) {
2512+
Register CalleeSaveBase = AArch64::FP;
2513+
if (int64_t CalleeSaveBaseOffset =
2514+
AFI->getCalleeSaveBaseToFrameRecordOffset()) {
2515+
// If we have have an non-zero offset to the non-SVE CS base we need to
2516+
// compute the base address by subtracting the offest in a temporary
2517+
// register first (to avoid briefly deallocating the SVE CS).
2518+
CalleeSaveBase = MBB.getParent()->getRegInfo().createVirtualRegister(
2519+
&AArch64::GPR64RegClass);
2520+
emitFrameOffset(MBB, RestoreBegin, DL, CalleeSaveBase, AArch64::FP,
2521+
StackOffset::getFixed(-CalleeSaveBaseOffset), TII,
25142522
MachineInstr::FrameDestroy);
25152523
}
2516-
} else {
2517-
if (AFI->getSVECalleeSavedStackSize()) {
2524+
// The code below will deallocate the stack space space by moving the
2525+
// SP to the start of the SVE callee-save area.
2526+
emitFrameOffset(MBB, RestoreBegin, DL, AArch64::SP, CalleeSaveBase,
2527+
StackOffset::getScalable(-SVECalleeSavedSize), TII,
2528+
MachineInstr::FrameDestroy);
2529+
} else if (BaseForSVEDealloc == AArch64::SP) {
2530+
if (SVECalleeSavedSize) {
25182531
// Deallocate the non-SVE locals first before we can deallocate (and
25192532
// restore callee saves) from the SVE area.
25202533
emitFrameOffset(

0 commit comments

Comments
 (0)