Skip to content

Commit dc1c00f

Browse files
authored
[StackFrameLayoutAnalysis] Use target-specific hook for SP offsets (llvm#100386)
StackFrameLayoutAnalysis currently calculates SP-relative offsets in a target-independent way via MachineFrameInfo offsets. This is incorrect for some Targets, e.g. AArch64, when there are scalable vector stack slots. This patch adds a virtual function to TargetFrameLowering to provide offsets from SP, with a default implementation matching what is currently used in StackFrameLayoutAnalysis, and refactors StackFrameLayoutAnalysis to use this function. Only non-zero scalable offsets are output by the analysis pass. An implementation of this function is added for AArch64 targets, which aims to provide correct SP offsets in most cases.
1 parent 91450f1 commit dc1c00f

File tree

6 files changed

+563
-26
lines changed

6 files changed

+563
-26
lines changed

llvm/include/llvm/CodeGen/TargetFrameLowering.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,13 @@ class TargetFrameLowering {
343343
return getFrameIndexReference(MF, FI, FrameReg);
344344
}
345345

346+
/// getFrameIndexReferenceFromSP - This method returns the offset from the
347+
/// stack pointer to the slot of the specified index. This function serves to
348+
/// provide a comparable offset from a single reference point (the value of
349+
/// the stack-pointer at function entry) that can be used for analysis.
350+
virtual StackOffset getFrameIndexReferenceFromSP(const MachineFunction &MF,
351+
int FI) const;
352+
346353
/// Returns the callee-saved registers as computed by determineCalleeSaves
347354
/// in the BitVector \p SavedRegs.
348355
virtual void getCalleeSaves(const MachineFunction &MF,

llvm/lib/CodeGen/StackFrameLayoutAnalysisPass.cpp

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -60,15 +60,15 @@ struct StackFrameLayoutAnalysisPass : public MachineFunctionPass {
6060
int Slot;
6161
int Size;
6262
int Align;
63-
int Offset;
63+
StackOffset Offset;
6464
SlotType SlotTy;
6565
bool Scalable;
6666

67-
SlotData(const MachineFrameInfo &MFI, const int ValOffset, const int Idx)
67+
SlotData(const MachineFrameInfo &MFI, const StackOffset Offset,
68+
const int Idx)
6869
: Slot(Idx), Size(MFI.getObjectSize(Idx)),
69-
Align(MFI.getObjectAlign(Idx).value()),
70-
Offset(MFI.getObjectOffset(Idx) - ValOffset), SlotTy(Invalid),
71-
Scalable(false) {
70+
Align(MFI.getObjectAlign(Idx).value()), Offset(Offset),
71+
SlotTy(Invalid), Scalable(false) {
7272
Scalable = MFI.getStackID(Idx) == TargetStackID::ScalableVector;
7373
if (MFI.isSpillSlotObjectIndex(Idx))
7474
SlotTy = SlotType::Spill;
@@ -79,10 +79,10 @@ struct StackFrameLayoutAnalysisPass : public MachineFunctionPass {
7979
}
8080

8181
// We use this to sort in reverse order, so that the layout is displayed
82-
// correctly. Scalable slots are sorted to the end of the list.
82+
// correctly.
8383
bool operator<(const SlotData &Rhs) const {
84-
return std::make_tuple(!Scalable, Offset) >
85-
std::make_tuple(!Rhs.Scalable, Rhs.Offset);
84+
return (Offset.getFixed() + Offset.getScalable()) >
85+
(Rhs.Offset.getFixed() + Rhs.Offset.getScalable());
8686
}
8787
};
8888

@@ -149,15 +149,27 @@ struct StackFrameLayoutAnalysisPass : public MachineFunctionPass {
149149
// For example we store the Offset in YAML as:
150150
// ...
151151
// - Offset: -8
152+
// - ScalableOffset: -16
153+
// Note: the ScalableOffset entries are added only for slots with non-zero
154+
// scalable offsets.
152155
//
153-
// But we print it to the CLI as
156+
// But we print it to the CLI as:
154157
// Offset: [SP-8]
158+
//
159+
// Or with non-zero scalable offset:
160+
// Offset: [SP-8-16 x vscale]
155161

156162
// Negative offsets will print a leading `-`, so only add `+`
157163
std::string Prefix =
158-
formatv("\nOffset: [SP{0}", (D.Offset < 0) ? "" : "+").str();
159-
Rem << Prefix << ore::NV("Offset", D.Offset)
160-
<< "], Type: " << ore::NV("Type", getTypeString(D.SlotTy))
164+
formatv("\nOffset: [SP{0}", (D.Offset.getFixed() < 0) ? "" : "+").str();
165+
Rem << Prefix << ore::NV("Offset", D.Offset.getFixed());
166+
167+
if (D.Offset.getScalable()) {
168+
Rem << ((D.Offset.getScalable() < 0) ? "" : "+")
169+
<< ore::NV("ScalableOffset", D.Offset.getScalable()) << " x vscale";
170+
}
171+
172+
Rem << "], Type: " << ore::NV("Type", getTypeString(D.SlotTy))
161173
<< ", Align: " << ore::NV("Align", D.Align)
162174
<< ", Size: " << ore::NV("Size", ElementCount::get(D.Size, D.Scalable));
163175
}
@@ -170,17 +182,22 @@ struct StackFrameLayoutAnalysisPass : public MachineFunctionPass {
170182
Rem << "\n " << ore::NV("DataLoc", Loc);
171183
}
172184

185+
StackOffset getStackOffset(const MachineFunction &MF,
186+
const MachineFrameInfo &MFI,
187+
const TargetFrameLowering *FI, int FrameIdx) {
188+
if (!FI)
189+
return StackOffset::getFixed(MFI.getObjectOffset(FrameIdx));
190+
191+
return FI->getFrameIndexReferenceFromSP(MF, FrameIdx);
192+
}
193+
173194
void emitStackFrameLayoutRemarks(MachineFunction &MF,
174195
MachineOptimizationRemarkAnalysis &Rem) {
175196
const MachineFrameInfo &MFI = MF.getFrameInfo();
176197
if (!MFI.hasStackObjects())
177198
return;
178199

179-
// ValOffset is the offset to the local area from the SP at function entry.
180-
// To display the true offset from SP, we need to subtract ValOffset from
181-
// MFI's ObjectOffset.
182200
const TargetFrameLowering *FI = MF.getSubtarget().getFrameLowering();
183-
const int ValOffset = (FI ? FI->getOffsetOfLocalArea() : 0);
184201

185202
LLVM_DEBUG(dbgs() << "getStackProtectorIndex =="
186203
<< MFI.getStackProtectorIndex() << "\n");
@@ -194,7 +211,7 @@ struct StackFrameLayoutAnalysisPass : public MachineFunctionPass {
194211
Idx != EndIdx; ++Idx) {
195212
if (MFI.isDeadObjectIndex(Idx))
196213
continue;
197-
SlotInfo.emplace_back(MFI, ValOffset, Idx);
214+
SlotInfo.emplace_back(MFI, getStackOffset(MF, MFI, FI, Idx), Idx);
198215
}
199216

200217
// sort the ordering, to match the actual layout in memory

llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,20 @@ TargetFrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI,
6161
MFI.getOffsetAdjustment());
6262
}
6363

64+
/// Returns the offset from the stack pointer to the slot of the specified
65+
/// index. This function serves to provide a comparable offset from a single
66+
/// reference point (the value of the stack-pointer at function entry) that can
67+
/// be used for analysis. This is the default implementation using
68+
/// MachineFrameInfo offsets.
69+
StackOffset
70+
TargetFrameLowering::getFrameIndexReferenceFromSP(const MachineFunction &MF,
71+
int FI) const {
72+
// To display the true offset from SP, we need to subtract the offset to the
73+
// local area from MFI's ObjectOffset.
74+
return StackOffset::getFixed(MF.getFrameInfo().getObjectOffset(FI) -
75+
getOffsetOfLocalArea());
76+
}
77+
6478
bool TargetFrameLowering::needsFrameIndexResolution(
6579
const MachineFunction &MF) const {
6680
return MF.getFrameInfo().hasStackObjects();

llvm/lib/Target/AArch64/AArch64FrameLowering.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2603,6 +2603,41 @@ AArch64FrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI,
26032603
/*ForSimm=*/false);
26042604
}
26052605

2606+
StackOffset
2607+
AArch64FrameLowering::getFrameIndexReferenceFromSP(const MachineFunction &MF,
2608+
int FI) const {
2609+
// This function serves to provide a comparable offset from a single reference
2610+
// point (the value of SP at function entry) that can be used for analysis,
2611+
// e.g. the stack-frame-layout analysis pass. It is not guaranteed to be
2612+
// correct for all objects in the presence of VLA-area objects or dynamic
2613+
// stack re-alignment.
2614+
2615+
const auto &MFI = MF.getFrameInfo();
2616+
2617+
int64_t ObjectOffset = MFI.getObjectOffset(FI);
2618+
2619+
// This is correct in the absence of any SVE stack objects.
2620+
StackOffset SVEStackSize = getSVEStackSize(MF);
2621+
if (!SVEStackSize)
2622+
return StackOffset::getFixed(ObjectOffset - getOffsetOfLocalArea());
2623+
2624+
const auto *AFI = MF.getInfo<AArch64FunctionInfo>();
2625+
if (MFI.getStackID(FI) == TargetStackID::ScalableVector) {
2626+
return StackOffset::get(-((int64_t)AFI->getCalleeSavedStackSize()),
2627+
ObjectOffset);
2628+
}
2629+
2630+
bool IsFixed = MFI.isFixedObjectIndex(FI);
2631+
bool IsCSR =
2632+
!IsFixed && ObjectOffset >= -((int)AFI->getCalleeSavedStackSize(MFI));
2633+
2634+
StackOffset ScalableOffset = {};
2635+
if (!IsFixed && !IsCSR)
2636+
ScalableOffset = -SVEStackSize;
2637+
2638+
return StackOffset::getFixed(ObjectOffset) + ScalableOffset;
2639+
}
2640+
26062641
StackOffset
26072642
AArch64FrameLowering::getNonLocalFrameIndexReference(const MachineFunction &MF,
26082643
int FI) const {

llvm/lib/Target/AArch64/AArch64FrameLowering.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ class AArch64FrameLowering : public TargetFrameLowering {
4141

4242
StackOffset getFrameIndexReference(const MachineFunction &MF, int FI,
4343
Register &FrameReg) const override;
44+
StackOffset getFrameIndexReferenceFromSP(const MachineFunction &MF,
45+
int FI) const override;
4446
StackOffset resolveFrameIndexReference(const MachineFunction &MF, int FI,
4547
Register &FrameReg, bool PreferFP,
4648
bool ForSimm) const;

0 commit comments

Comments
 (0)