Index: llvm/lib/Target/AArch64/AArch64FrameLowering.cpp =================================================================== --- llvm/lib/Target/AArch64/AArch64FrameLowering.cpp +++ llvm/lib/Target/AArch64/AArch64FrameLowering.cpp @@ -1019,7 +1019,8 @@ if (HasFP) { // Only set up FP if we actually need to. - int FPOffset = isTargetDarwin(MF) ? (AFI->getCalleeSavedStackSize() - 16) : 0; + int FPOffset = isTargetDarwin(MF) ? (AFI->getCalleeSavedStackSize() - 16) + : AFI->getFrameRecordOffset(); if (CombineSPBump) FPOffset += AFI->getLocalStackSize(); @@ -1615,7 +1616,8 @@ // be able to save any instructions. if (!IsFunclet && (MFI.hasVarSizedObjects() || AFI->isStackRealigned())) { int64_t OffsetToFrameRecord = - isTargetDarwin(MF) ? (-(int64_t)AFI->getCalleeSavedStackSize() + 16) : 0; + isTargetDarwin(MF) ? (-(int64_t)AFI->getCalleeSavedStackSize() + 16) + : -AFI->getFrameRecordOffset();; emitFrameOffset(MBB, LastPopI, DL, AArch64::SP, AArch64::FP, {OffsetToFrameRecord, MVT::i8}, TII, MachineInstr::FrameDestroy, false, NeedsWinCFI); @@ -2061,6 +2063,11 @@ (RPI.isScalable() && RPI.Offset >= -256 && RPI.Offset <= 255)) && "Offset out of bounds for LDP/STP immediate"); + // Save the offset to frame record so that the FP register can point to the + // innermost frame record (spilled FP and LR registers). + if (NeedsFrameRecord && RPI.Reg1 == AArch64::LR && RPI.Reg2 == AArch64::FP) + AFI->setFrameRecordOffset(Offset); + RegPairs.push_back(RPI); if (RPI.isPaired()) ++i; Index: llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h =================================================================== --- llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h +++ llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h @@ -126,6 +126,10 @@ // stack slot. unsigned TaggedBasePointerOffset = 0; + // Offset from SP-at-entry to frame record (i.e. the spilled frame pointer + // and link address). + int FrameRecordOffset = 0; + public: AArch64FunctionInfo() = default; @@ -325,6 +329,13 @@ TaggedBasePointerOffset = Offset; } + int getFrameRecordOffset() const { + return FrameRecordOffset; + } + void setFrameRecordOffset(int Offset) { + FrameRecordOffset = Offset; + } + private: // Hold the lists of LOHs. MILOHContainer LOHContainerSet; Index: llvm/test/CodeGen/AArch64/framelayout-frame-record.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/AArch64/framelayout-frame-record.ll @@ -0,0 +1,19 @@ +; RUN: llc < %s -mtriple=aarch64--linux-gnu | FileCheck %s + +target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" +target triple = "aarch64--linux-gnu" + +declare void @escape.i64(i64) +declare void @escape.double(double) + +define void @test_frame_record_offset(i64 %a, i64 %b, double %c, double %d) "no-frame-pointer-elim"="true" { +; CHECK-LABEL: test_frame_record_offset: +; CHECK: stp x29, x30, [sp, #[[OFFSET:[0-9]+]]] +; CHECK: add x29, sp, #[[OFFSET]] + + call void @escape.i64(i64 %a) + call void @escape.i64(i64 %b) + call void @escape.double(double %c) + call void @escape.double(double %d) + ret void +}