Skip to content

Commit a0aed80

Browse files
committed
Fix frame pointer layout on AArch64 Linux.
When floating point callee-saved registers were used, the frame pointer would incorrectly point to the bottom of the CSR space (containing saved floating-point registers), rather than to the frame record. While all frame offsets were calculated consistently, resulting in working code, this prevented stack walkers from being about to traverse the frame list.
1 parent bda8fbe commit a0aed80

File tree

2 files changed

+54
-6
lines changed

2 files changed

+54
-6
lines changed

llvm/lib/Target/AArch64/AArch64FrameLowering.cpp

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1185,7 +1185,26 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
11851185
// For funclets the FP belongs to the containing function.
11861186
if (!IsFunclet && HasFP) {
11871187
// Only set up FP if we actually need to.
1188-
int64_t FPOffset = isTargetDarwin(MF) ? (AFI->getCalleeSavedStackSize() - 16) : 0;
1188+
int64_t FPOffset;
1189+
1190+
// The frame pointer needs to point to the location of the frame record
1191+
// (x28 and x29) within the callee saved register space.
1192+
if (isTargetDarwin(MF)) {
1193+
// On Darwin, these are located at the top of the CSR space.
1194+
FPOffset = (AFI->getCalleeSavedStackSize() - 16);
1195+
} else {
1196+
// On other systems, these are located in the middle of the CSR space,
1197+
// after the other GPRs and before the FPRs.
1198+
assert(MFI.isCalleeSavedInfoValid() && "CalleeSavedInfo not calculated");
1199+
if (MFI.getCalleeSavedInfo().empty()) {
1200+
FPOffset = 0;
1201+
} else {
1202+
FPOffset = AFI->getCalleeSavedStackSize(MFI, [](unsigned Reg) {
1203+
return AArch64::FPR64RegClass.contains(Reg) ||
1204+
AArch64::FPR128RegClass.contains(Reg);
1205+
});
1206+
}
1207+
}
11891208

11901209
if (CombineSPBump)
11911210
FPOffset += AFI->getLocalStackSize();
@@ -1842,8 +1861,16 @@ static StackOffset getFPOffset(const MachineFunction &MF, int64_t ObjectOffset)
18421861

18431862
unsigned FixedObject =
18441863
getFixedObjectSize(MF, AFI, IsWin64, /*IsFunclet=*/false);
1845-
unsigned FPAdjust = isTargetDarwin(MF)
1846-
? 16 : AFI->getCalleeSavedStackSize(MF.getFrameInfo());
1864+
1865+
// Compensate for the position of the frame record within the callee-saved
1866+
// register space. On Darwin, this is a fixed offset. On other systems,
1867+
// this is determined by the number of callee-saved GPRs, excluding FPRs.
1868+
unsigned FPAdjust =
1869+
isTargetDarwin(MF)
1870+
? 16
1871+
: AFI->getCalleeSavedStackSize(MF.getFrameInfo(), [](unsigned Reg) {
1872+
return AArch64::GPR64RegClass.contains(Reg);
1873+
});
18471874
return {ObjectOffset + FixedObject + FPAdjust, MVT::i8};
18481875
}
18491876

llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -194,9 +194,15 @@ class AArch64FunctionInfo final : public MachineFunctionInfo {
194194
// When CalleeSavedStackSize has not been set (for example when
195195
// some MachineIR pass is run in isolation), then recalculate
196196
// the CalleeSavedStackSize directly from the CalleeSavedInfo.
197+
// RegisterFilter is a predicate to calculate the stack size for
198+
// subsets of the callee-saved registers. It should return true
199+
// for registers that should be included in the size calculation,
200+
// and false otherwise.
197201
// Note: This information can only be recalculated after PEI
198202
// has assigned offsets to the callee save objects.
199-
unsigned getCalleeSavedStackSize(const MachineFrameInfo &MFI) const {
203+
unsigned getCalleeSavedStackSize(
204+
const MachineFrameInfo &MFI,
205+
llvm::function_ref<bool(unsigned)> RegisterFilter = nullptr) const {
200206
bool ValidateCalleeSavedStackSize = false;
201207

202208
#ifndef NDEBUG
@@ -206,25 +212,40 @@ class AArch64FunctionInfo final : public MachineFunctionInfo {
206212
ValidateCalleeSavedStackSize = HasCalleeSavedStackSize;
207213
#endif
208214

209-
if (!HasCalleeSavedStackSize || ValidateCalleeSavedStackSize) {
215+
if (RegisterFilter || !HasCalleeSavedStackSize ||
216+
ValidateCalleeSavedStackSize) {
210217
assert(MFI.isCalleeSavedInfoValid() && "CalleeSavedInfo not calculated");
211218
if (MFI.getCalleeSavedInfo().empty())
212219
return 0;
213220

214221
int64_t MinOffset = std::numeric_limits<int64_t>::max();
215222
int64_t MaxOffset = std::numeric_limits<int64_t>::min();
223+
224+
bool AnyRegistersCounted = false;
216225
for (const auto &Info : MFI.getCalleeSavedInfo()) {
226+
if (RegisterFilter) {
227+
unsigned Reg = Info.getReg();
228+
if (!RegisterFilter(Reg))
229+
continue;
230+
}
231+
232+
AnyRegistersCounted = true;
217233
int FrameIdx = Info.getFrameIdx();
218234
if (MFI.getStackID(FrameIdx) != TargetStackID::Default)
219235
continue;
220236
int64_t Offset = MFI.getObjectOffset(FrameIdx);
221237
int64_t ObjSize = MFI.getObjectSize(FrameIdx);
222238
MinOffset = std::min<int64_t>(Offset, MinOffset);
223239
MaxOffset = std::max<int64_t>(Offset + ObjSize, MaxOffset);
240+
AnyRegistersCounted = true;
224241
}
225242

243+
if (!AnyRegistersCounted)
244+
return 0;
245+
226246
unsigned Size = alignTo(MaxOffset - MinOffset, 16);
227-
assert((!HasCalleeSavedStackSize || getCalleeSavedStackSize() == Size) &&
247+
assert((RegisterFilter || !HasCalleeSavedStackSize ||
248+
getCalleeSavedStackSize() == Size) &&
228249
"Invalid size calculated for callee saves");
229250
return Size;
230251
}

0 commit comments

Comments
 (0)