Skip to content

Commit d8e8ab7

Browse files
authored
[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 8a469da commit d8e8ab7

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
@@ -2578,20 +2578,33 @@ void AArch64FrameLowering::emitEpilogue(MachineFunction &MF,
25782578
DeallocateAfter, TII, MachineInstr::FrameDestroy, false,
25792579
NeedsWinCFI, &HasWinCFI);
25802580
} else if (SVEStackSize) {
2581-
// If we have stack realignment or variable sized objects on the stack,
2582-
// restore the stack pointer from the frame pointer prior to SVE CSR
2583-
// restoration.
2584-
if (AFI->isStackRealigned() || MFI.hasVarSizedObjects()) {
2585-
if (int64_t CalleeSavedSize = AFI->getSVECalleeSavedStackSize()) {
2586-
// Set SP to start of SVE callee-save area from which they can
2587-
// be reloaded. The code below will deallocate the stack space
2588-
// space by moving FP -> SP.
2589-
emitFrameOffset(MBB, RestoreBegin, DL, AArch64::SP, AArch64::FP,
2590-
StackOffset::getScalable(-CalleeSavedSize), TII,
2581+
int64_t SVECalleeSavedSize = AFI->getSVECalleeSavedStackSize();
2582+
// If we have stack realignment or variable-sized objects we must use the
2583+
// FP to restore SVE callee saves (as there is an unknown amount of
2584+
// data/padding between the SP and SVE CS area).
2585+
Register BaseForSVEDealloc =
2586+
(AFI->isStackRealigned() || MFI.hasVarSizedObjects()) ? AArch64::FP
2587+
: AArch64::SP;
2588+
if (SVECalleeSavedSize && BaseForSVEDealloc == AArch64::FP) {
2589+
Register CalleeSaveBase = AArch64::FP;
2590+
if (int64_t CalleeSaveBaseOffset =
2591+
AFI->getCalleeSaveBaseToFrameRecordOffset()) {
2592+
// If we have have an non-zero offset to the non-SVE CS base we need to
2593+
// compute the base address by subtracting the offest in a temporary
2594+
// register first (to avoid briefly deallocating the SVE CS).
2595+
CalleeSaveBase = MBB.getParent()->getRegInfo().createVirtualRegister(
2596+
&AArch64::GPR64RegClass);
2597+
emitFrameOffset(MBB, RestoreBegin, DL, CalleeSaveBase, AArch64::FP,
2598+
StackOffset::getFixed(-CalleeSaveBaseOffset), TII,
25912599
MachineInstr::FrameDestroy);
25922600
}
2593-
} else {
2594-
if (AFI->getSVECalleeSavedStackSize()) {
2601+
// The code below will deallocate the stack space space by moving the
2602+
// SP to the start of the SVE callee-save area.
2603+
emitFrameOffset(MBB, RestoreBegin, DL, AArch64::SP, CalleeSaveBase,
2604+
StackOffset::getScalable(-SVECalleeSavedSize), TII,
2605+
MachineInstr::FrameDestroy);
2606+
} else if (BaseForSVEDealloc == AArch64::SP) {
2607+
if (SVECalleeSavedSize) {
25952608
// Deallocate the non-SVE locals first before we can deallocate (and
25962609
// restore callee saves) from the SVE area.
25972610
emitFrameOffset(

0 commit comments

Comments
 (0)